client_block(2) CX/UX client_block(2)
NAME
clientblock, clientwake1, clientwakechan - client-server
thread coordination
SYNOPSIS
#include <sys/types.h>
#include <sys/time.h>
#include <sys/threadsynch.h>
int clientblock (server, chan, options, m, r, timeout)
tidt server;
int chan, options;
struct spinmutex *m;
struct reschedvar *r;
struct timeval *timeout;
int clientwake1 (server, client, r)
tidt server, client;
struct reschedvar *r;
int clientwakechan (server, chan, r)
tidt server;
int chan;
struct reschedvar *r;
DESCRIPTION
When one thread requests service from another, the former
thread is called a "client", and the latter thread is called
a "server." To control priority inversion, a server should
have a priority at least as high as any of its clients. The
routines described here provide a priority inheritance
mechanism.
clientblock blocks the calling thread (a client) and estab-
lishes a formal client-server relationship with another
thread (the server). Clientwake1 and clientwakechan wake
threads that are blocked in clientblock.
clientblock releases spinlock m, decrements the number of
rescheduling locks in r, and blocks the caller. The unlock
and block operations are atomic to guarantee that the caller
does not miss a wakeup. Server's priority will be at least
as high as the caller's while the caller is blocked. m and
r are optional and may be specified as NULL.
If the options flag is 1 the server will be woken as in
serverwake1(2).
The chan parameter groups related clients of a server. It
is used by clientwakechan.
Page 1 CX/UX Programmer's Reference Manual
client_block(2) CX/UX client_block(2)
If timeout is not NULL, it specifies the maximum length of
time the caller will be blocked. If timeout is NULL, the
caller is blocked indefinitely.
The real or effective user ID of the caller must match the
real or effective user ID of server, unless the effective
user ID of the caller is super-user.
The caller should be prepared for premature returns; that
is, it should re-test the condition that originally caused
it to block. Upon return there is no guarantee that the
condition blocking the caller has changed.
Clientwake1 wakes client, if it is blocked in clientblock
requesting service from server, and decrements the number of
rescheduling locks in r. If client is not blocked under
these conditions, clientwake1 has no effect on it. A value
of 0 for server refers to the calling thread. (In this
implementation, server must be 0.)
The real or effective user ID of the caller must match the
real or effective user ID of client, unless the effective
user ID of the caller is super-user.
Clientwakechan wakes all of the clients grouped under chan
requesting service from server, and decrements the number of
rescheduling locks in r. A value of 0 for server refers to
the calling thread. (In this implementation, server must be
0.) A value of 0 for chan wakes ALL of the server's
clients.
The real or effective user ID of the caller must match the
real or effective user ID of the clients, unless the effec-
tive user ID of the caller is super-user.
EXAMPLES
Priority inversion is a condition wherein one or more low
priority threads prevent the progress of a high priority
thread. The most often cited example is that of a low
priority thread L being preempted in a critical region. A
high priority thread H attempting to enter the critical
region will block until L leaves the critical region. How-
ever, threads in the priority gap between H and L prevent L
from running. If L were to inherit H's priority, the gap
would close and L would run until it was preempted by H upon
exit from the critical region.
The code fragments below implement priority inheritance in
sleepy-wait mutual exclusion. Let
01 struct sleepmutex {
02 struct spinmutex mx;
Page 2 CX/UX Programmer's Reference Manual
client_block(2) CX/UX client_block(2)
03 tidt owner;
04 int waiters;
05 };
represent a sleepy-wait mutex. The owner field identifies
the thread that owns the mutex, the waiters field indicates
whether threads are blocked on the mutex, and the mx field
serializes access to the mutex. Let rv represent the run-
ning thread's rescheduling variable, and spin_acquire and
spin_release represent primitives that lock and unlock spin-
locks and rescheduling variables (see spintrylock(2)).
A mutex may be locked as follows.
11 void
12 sleeplock (s)
13 struct sleepmutex *s;
14 {
15 spinacquire (&s->mx, &rv);
16 while (s->owner) {
17 s->waiters = 1;
18 clientblock (s->owner, s, 0, &s->mx, &rv, 0);
19 spinacquire (&s->mx, &rv);
20 }
21 s->owner = rv.rvtid;
22 spinrelease (&s->mx, &rv);
23 }
Although perhaps an unusual interpretation of the client-
server relationship, the owner of the mutex is considered to
be a server, and the waiting threads are considered to be
its clients. clientblock guarantees that the owner's
priority is at least as high as any of the waiting threads.
This example assumes that a mutex appears at the same loca-
tion in every thread's address space, so the address of the
mutex is used as the chan argument to clientblock to dis-
tinguish one mutex's waiters from another's.
A mutex may be unlocked as follows.
31 void
32 sleepunlock (s)
33 struct sleepmutex *s;
34 {
35 int werewaiters;
36
37 spinacquire (&s->mx, &rv);
38 if (s->owner != rv.rvtid) {
39 Indicate error condition.
40 }
41 s->owner = 0;
42 werewaiters = s->waiters;
Page 3 CX/UX Programmer's Reference Manual
client_block(2) CX/UX client_block(2)
43 s->waiters = 0;
44 spinunlock (&s->mx);
45
46 if (werewaiters)
47 clientwakechan (0, s, &rv);
48 else
49 reschedunlock (&rv);
50 }
When an owner releases a mutex all of the waiters are woken.
The newly awakened waiters re-contend for the mutex when
they execute. One will become the new owner of the mutex,
while the others block and establish new client-server rela-
tionships.
RETURN VALUE
Upon successful completion 0 is returned. Otherwise, -1 is
returned and errno is set to indicate the error.
ERRORS
These routines will fail if any of the following are true:
[EFAULT] A bad address was specified for one of the
arguments.
[EINVAL] The spinlock specified in m was not in the
locked state.
[EINVAL] The timeout was invalid.
[EINVAL] The rescheduling variable specified in r was
not the caller's rescheduling variable.
[EINVAL] The number of rescheduling locks in r was <=
0.
[ESRCH] No thread could be found with the specified
ID.
[EPERM] The user ID of the calling thread was not
super-user, and its real or effective user ID
did not match the real or effective user ID
of the target thread.
[EINTR] The system call was interrupted by a signal.
[ETIME] The system call timed out.
SEE ALSO
CX/UX Programmer's Guide.
gettid(2), reschedcntl(2), spintrylock(2),
serverblock(2).
Page 4 CX/UX Programmer's Reference Manual