server_block(2) — CX/UX
NAME
server_block, server_wake1, server_wakevec − client/server thread coordination
SYNOPSIS
#include <sys/types.h>
#include <sys/time.h>
#include <sys/thread_synch.h>
int server_block (options, r, timeout)
int options;
struct resched_var ∗r;
struct timeval ∗timeout;
int server_wake1 (server, r)
tid_t server;
struct resched_var ∗r;
int server_wakevec (servers, nservers, r)
tid_t ∗servers;
int nservers;
struct resched_var ∗r;
DESCRIPTION
server_block blocks the calling thread if no wake-up has occurred since the last return from server_block. If a wake-up has occurred, server_block returns immediately.
Options must be zero.
If r is not NULL, server_block decrements the number of locks in the rescheduling variable.
If timeout is not NULL, it specifies the maximum length of time the caller will be blocked.
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.
Server_wake1 wakes thread server if it is blocked in server_block. If server is not blocked in server_block, the wake-up will be applied to the next call to server_block.
If r is not NULL, server_wake1 decrements the number of locks in the rescheduling variable.
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.
Server_wakevec serves the same purpose as server_wake1, except that a vector of threads may be specified rather than one thread.
EXAMPLES
Suppose that producer and consumer threads exchange data through a mailbox in shared memory. When the mailbox is empty, consumers block until data arrives. When producers deposit new data, they wake the waiting consumers.
In the pseudo-code that follows, let
01 struct mailbox {
02struct spin_mutex mx;/∗ serializes access to mailbox ∗/
03queue_of consumers;/∗ waiting consumers ∗/
04queue_of data;/∗ the data, type varies ∗/
05 };
represent a mailbox in shared memory, rv represent a rescheduling variable, and spin_acquire and spin_release represent primitives that lock and unlock spinlocks and rescheduling variables (see spin_trylock(2)). Consumers extract data from the mailbox as follows.
11 void
12 consume (box, data)
13struct mailbox ∗box;
14any_t ∗data;
15 {
16spin_acquire (&box->mx, &rv);
17while (box->data == empty) {
18enqueue (box->consumers, rv.rv_tid);
19spin_unlock (&box->mx);
20server_block (0, &rv, 0);
21spin_acquire (&box->mx, &rv);
22}
23∗data = dequeue (box->data);
24spin_release (&box->mx, &rv);
25 }
The mailbox is a shared data structure requiring serialization. Consumer threads lock the mailbox to test for the presence of and ultimately to extract the data. When they wait, consumers unlock the mailbox to allow producers to deposit new data. Consumers re-check the mailbox when they awaken because there is no guarantee that the mailbox will contain data.
Producers store data into the mailbox as follows. This example assumes that at most one consumer can benefit from the arrival of the new data, so producers wake one rather than all consumers.
31 void
32 produce (box, data)
33struct mailbox ∗box;
34any_t data;
35 {
36spin_acquire (&box->mx, &rv);
37enqueue (box->data, data);
38if (box->consumers == empty)
39spin_release (&box->mx, &rv);
40else {
41tid_t tid = dequeue (box->consumers);
42spin_unlock (&box->mx);
43server_wake1 (tid, &rv);
44}
45 }
Producers signal the arrival of new data only when there is a waiting consumer, and do so AFTER they unlock the mailbox. The first act of a newly awakened consumer is to lock the mailbox. If a producer were to awaken a consumer before it unlocked the mailbox, the consumer may run only to find the mailbox locked. Furthermore, spinlocks should only be held for short periods of time. Unlocking the mailbox after the call to server_wake1 would lengthen its hold time tremendously. Also note that rescheduling remains disabled until the call to server_wake1 in order to prevent unnecessary context switching.
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] Options was non-zero.
[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 less than or equal to 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), resched_cntl(2), spin_trylock(2), client_block(2).
CX/UX Programmer’s Reference Manual