MON_CREATE(3L)

NAME
mon_create, mon_destroy, mon_enter, mon_exit, mon_enumerate, mon_waiters, mon_cond_enter, mon_break, MONITOR, SAMEMON - LWP routines to manage critical sections

SYNOPSIS

#include <lwp/lwp.h>

int mon_create(mid)
mon_t *mid;

int mon_destroy(mid)
mon_t mid;

int mon_enter(mid)
mon_t mid;

int mon_exit(mid)
mon_t mid;

int mon_enumerate(vec, maxsize)
mon_t vec[];	/* list of all monitors */
int maxsize;	/* max size of vec */

int mon_waiters(mid, owner, vec, maxsize)
mon_t mid;		/* monitor in question */
thread_t *owner;	/* which thread owns the monitor */
thread_t vec[];		/* list of blocked threads */
int maxsize;		/* max size of vec */

int mon_cond_enter(mid)
mon_t mid;

int mon_break(mid)
mon_t mid;

void MONITOR(mid)
mon_t mid;

int SAMEMON(m1, m2)
mon_t m1;
mon_t m2;

DESCRIPTION

Monitors are used to synchronize access to common resources. Although it is possible (on a uniprocessor) to use knowledge of how scheduling priorities work to serialize access to a resource, monitors (and condition variables) provide a general tool to provide the necessary synchronization.

mon_create() creates a new monitor and returns its identity in mid. mon_destroy() destroys a monitor, as well as any conditions bound to it (see cv_create(3L)). Because the lifetime of a monitor can transcend the lifetime of the LWP that created it, monitor destruction is not automatic upon LWP destruction.

mon_enter() blocks the calling thread (if the monitor is in use) until the monitor becomes free by being exited or by waiting on a condition (see cv_create(3L)). Threads unable to gain entry into the monitor are queued for monitor service by the priority of the thread requesting monitor access, FCFS within a priority. Monitor calls may nest. If, while holding monitor M1 a request for monitor M2 is made, M1 will be held until M2 can be acquired.

mon_cond_enter() will enter the monitor only if the monitor is not busy. Otherwise, an error is returned.

mon_enter() and mon_cond_enter() will allow a thread which already has the monitor to reenter the monitor. In this case, the nesting level of monitor entries is returned. Thus, the first time a monitor is entered, mon_enter() returns 0. The next time the monitor is entered, mon_enter() returns 1. mon_exit() frees the current monitor and allows the next thread blocked on the monitor (if any) to enter the monitor. However, if a monitor is entered more than once, mon_exit() returns the previous monitor nesting level without freeing the monitor to other threads. Thus, if the monitor was not reentered, mon_exit() returns 0.

mon_enumerate() lists all the monitors in the system. The vector supplied is filled in with the ID's of the monitors. maxsize is used to avoid exceeding the capacity of the list. If the number of monitors is greater than maxsize, only maxsize monitor ID's are filled in vec.

mon_waiters() puts the thread that currently owns the monitor in owner and all threads blocked on the monitor in vec (subject to the maxsize limitation), and returns the number of waiting threads.

mon_break() forces the release of a monitor lock not necessarily held by the invoking thread. This enables the next thread blocked on the monitor to enter it.

MONITOR is a macro that can be used at the start of a procedure to indicate that the procedure is a monitor. It uses the exception handling mechanism to ensure that the monitor is exited automatically when the procedure exits. Ordinarily, this single macro replaces paired mon_enter()- mon_exit() calls in a monitor procedure.

The SAMEMON macro is a convenient predicate used to compare two monitors for equality.

Monitor locks are released automatically when the LWP holding them dies. This may have implications for the validity of the monitor invariant (a condition that is always true outside of the monitor) if a thread unexpectedly terminates.

RETURN VALUES

mon_create() returns the ID of a new monitor.

mon_destroy() returns:

0   on success.

-1  on failure.

mon_enter() returns the nesting level of the monitor.

mon_exit() returns the previous nesting level on success. On failure, it returns -1.

mon_enumerate() returns the total number of monitors.

mon_waiters() returns the number of threads waiting for the monitor.

mon_cond_enter() returns the nesting level of the monitor if the monitor is not busy. If the monitor is busy, it returns -1.

mon_break() returns:

0   on success.

-1  on failure.

The macro SAMEMON() returns 1 if the monitors specified by m1 and m2 are equal. It returns 0 otherwise.

ERRORS

mon_break() will fail if one or more of the following are true:

LE_NONEXIST
    Attempt to break lock on non-existent monitor.

LE_NOTOWNED
    Attempt to break a monitor lock that is not set.

mon_cond_enter() will fail if one or more of the following are true:

LE_INUSE
    The requested monitor is being used by another thread.

LE_NONEXIST
    Attempt to destroy non-existent monitor.

mon_destroy() will fail if one or more of the following are true:

LE_INUSE
    Attempt to destroy a monitor that has threads blocked on it.

LE_NONEXIST
    Attempt to destroy non-existent monitor.

mon_exit() will fail if one or more of the following are true:

LE_INVALIDARG
    Attempt to exit a monitor that the thread does not own.

LE_NONEXIST
    Attempt to exit non-existent monitor.

SEE ALSO
cv_create(3L)

BUGS

There should be language support to enforce the monitor enter-exit discipline.