xref: /plan9/sys/src/cmd/gs/src/gp_psync.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier /* Copyright (C) 1999, 2000 Aladdin Enterprises.  All rights reserved.
2*7dd7cddfSDavid du Colombier 
3*7dd7cddfSDavid du Colombier    This file is part of Aladdin Ghostscript.
4*7dd7cddfSDavid du Colombier 
5*7dd7cddfSDavid du Colombier    Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
6*7dd7cddfSDavid du Colombier    or distributor accepts any responsibility for the consequences of using it,
7*7dd7cddfSDavid du Colombier    or for whether it serves any particular purpose or works at all, unless he
8*7dd7cddfSDavid du Colombier    or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
9*7dd7cddfSDavid du Colombier    License (the "License") for full details.
10*7dd7cddfSDavid du Colombier 
11*7dd7cddfSDavid du Colombier    Every copy of Aladdin Ghostscript must include a copy of the License,
12*7dd7cddfSDavid du Colombier    normally in a plain ASCII text file named PUBLIC.  The License grants you
13*7dd7cddfSDavid du Colombier    the right to copy, modify and redistribute Aladdin Ghostscript, but only
14*7dd7cddfSDavid du Colombier    under certain conditions described in the License.  Among other things, the
15*7dd7cddfSDavid du Colombier    License requires that the copyright notice and this notice be preserved on
16*7dd7cddfSDavid du Colombier    all copies.
17*7dd7cddfSDavid du Colombier  */
18*7dd7cddfSDavid du Colombier 
19*7dd7cddfSDavid du Colombier /*$Id: gp_psync.c,v 1.1 2000/03/09 08:40:41 lpd Exp $ */
20*7dd7cddfSDavid du Colombier /* POSIX pthreads threads / semaphore / monitor implementation */
21*7dd7cddfSDavid du Colombier #include "std.h"
22*7dd7cddfSDavid du Colombier #include "malloc_.h"
23*7dd7cddfSDavid du Colombier #include <pthread.h>
24*7dd7cddfSDavid du Colombier #include "gserror.h"
25*7dd7cddfSDavid du Colombier #include "gserrors.h"
26*7dd7cddfSDavid du Colombier #include "gpsync.h"
27*7dd7cddfSDavid du Colombier 
28*7dd7cddfSDavid du Colombier /*
29*7dd7cddfSDavid du Colombier  * Thanks to Larry Jones <larry.jones@sdrc.com> for this revision of
30*7dd7cddfSDavid du Colombier  * Aladdin's original code into a form that depends only on POSIX APIs.
31*7dd7cddfSDavid du Colombier  */
32*7dd7cddfSDavid du Colombier 
33*7dd7cddfSDavid du Colombier /*
34*7dd7cddfSDavid du Colombier  * Some old versions of the pthreads library define
35*7dd7cddfSDavid du Colombier  * pthread_attr_setdetachstate as taking a Boolean rather than an enum.
36*7dd7cddfSDavid du Colombier  * Compensate for this here.
37*7dd7cddfSDavid du Colombier  */
38*7dd7cddfSDavid du Colombier #ifndef PTHREAD_CREATE_DETACHED
39*7dd7cddfSDavid du Colombier #  define PTHREAD_CREATE_DETACHED 1
40*7dd7cddfSDavid du Colombier #endif
41*7dd7cddfSDavid du Colombier 
42*7dd7cddfSDavid du Colombier /* ------- Synchronization primitives -------- */
43*7dd7cddfSDavid du Colombier 
44*7dd7cddfSDavid du Colombier /* Semaphore supports wait/signal semantics */
45*7dd7cddfSDavid du Colombier 
46*7dd7cddfSDavid du Colombier typedef struct pt_semaphore_t {
47*7dd7cddfSDavid du Colombier     int count;
48*7dd7cddfSDavid du Colombier     pthread_mutex_t mutex;
49*7dd7cddfSDavid du Colombier     pthread_cond_t cond;
50*7dd7cddfSDavid du Colombier } pt_semaphore_t;
51*7dd7cddfSDavid du Colombier 
52*7dd7cddfSDavid du Colombier uint
53*7dd7cddfSDavid du Colombier gp_semaphore_sizeof(void)
54*7dd7cddfSDavid du Colombier {
55*7dd7cddfSDavid du Colombier     return sizeof(pt_semaphore_t);
56*7dd7cddfSDavid du Colombier }
57*7dd7cddfSDavid du Colombier 
58*7dd7cddfSDavid du Colombier /*
59*7dd7cddfSDavid du Colombier  * This procedure should really check errno and return something
60*7dd7cddfSDavid du Colombier  * more informative....
61*7dd7cddfSDavid du Colombier  */
62*7dd7cddfSDavid du Colombier #define SEM_ERROR_CODE(scode)\
63*7dd7cddfSDavid du Colombier   (scode != 0 ? gs_note_error(gs_error_ioerror) : 0)
64*7dd7cddfSDavid du Colombier 
65*7dd7cddfSDavid du Colombier int
66*7dd7cddfSDavid du Colombier gp_semaphore_open(gp_semaphore * sema)
67*7dd7cddfSDavid du Colombier {
68*7dd7cddfSDavid du Colombier     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
69*7dd7cddfSDavid du Colombier     int scode;
70*7dd7cddfSDavid du Colombier 
71*7dd7cddfSDavid du Colombier     if (!sema)
72*7dd7cddfSDavid du Colombier 	return -1;		/* semaphores are not movable */
73*7dd7cddfSDavid du Colombier     sem->count = 0;
74*7dd7cddfSDavid du Colombier     scode = pthread_mutex_init(&sem->mutex, NULL);
75*7dd7cddfSDavid du Colombier     if (scode == 0)
76*7dd7cddfSDavid du Colombier 	scode = pthread_cond_init(&sem->cond, NULL);
77*7dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
78*7dd7cddfSDavid du Colombier }
79*7dd7cddfSDavid du Colombier 
80*7dd7cddfSDavid du Colombier int
81*7dd7cddfSDavid du Colombier gp_semaphore_close(gp_semaphore * sema)
82*7dd7cddfSDavid du Colombier {
83*7dd7cddfSDavid du Colombier     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
84*7dd7cddfSDavid du Colombier     int scode, scode2;
85*7dd7cddfSDavid du Colombier 
86*7dd7cddfSDavid du Colombier     scode = pthread_cond_destroy(&sem->cond);
87*7dd7cddfSDavid du Colombier     scode2 = pthread_mutex_destroy(&sem->mutex);
88*7dd7cddfSDavid du Colombier     if (scode == 0)
89*7dd7cddfSDavid du Colombier 	scode = scode2;
90*7dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
91*7dd7cddfSDavid du Colombier }
92*7dd7cddfSDavid du Colombier 
93*7dd7cddfSDavid du Colombier int
94*7dd7cddfSDavid du Colombier gp_semaphore_wait(gp_semaphore * sema)
95*7dd7cddfSDavid du Colombier {
96*7dd7cddfSDavid du Colombier     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
97*7dd7cddfSDavid du Colombier     int scode, scode2;
98*7dd7cddfSDavid du Colombier 
99*7dd7cddfSDavid du Colombier     scode = pthread_mutex_lock(&sem->mutex);
100*7dd7cddfSDavid du Colombier     if (scode != 0)
101*7dd7cddfSDavid du Colombier 	return SEM_ERROR_CODE(scode);
102*7dd7cddfSDavid du Colombier     while (sem->count == 0) {
103*7dd7cddfSDavid du Colombier         scode = pthread_cond_wait(&sem->cond, &sem->mutex);
104*7dd7cddfSDavid du Colombier         if (scode != 0)
105*7dd7cddfSDavid du Colombier 	    break;
106*7dd7cddfSDavid du Colombier     }
107*7dd7cddfSDavid du Colombier     if (scode == 0)
108*7dd7cddfSDavid du Colombier 	--sem->count;
109*7dd7cddfSDavid du Colombier     scode2 = pthread_mutex_unlock(&sem->mutex);
110*7dd7cddfSDavid du Colombier     if (scode == 0)
111*7dd7cddfSDavid du Colombier 	scode = scode2;
112*7dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
113*7dd7cddfSDavid du Colombier }
114*7dd7cddfSDavid du Colombier 
115*7dd7cddfSDavid du Colombier int
116*7dd7cddfSDavid du Colombier gp_semaphore_signal(gp_semaphore * sema)
117*7dd7cddfSDavid du Colombier {
118*7dd7cddfSDavid du Colombier     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
119*7dd7cddfSDavid du Colombier     int scode, scode2;
120*7dd7cddfSDavid du Colombier 
121*7dd7cddfSDavid du Colombier     scode = pthread_mutex_lock(&sem->mutex);
122*7dd7cddfSDavid du Colombier     if (scode != 0)
123*7dd7cddfSDavid du Colombier 	return SEM_ERROR_CODE(scode);
124*7dd7cddfSDavid du Colombier     if (sem->count++ == 0)
125*7dd7cddfSDavid du Colombier 	scode = pthread_cond_signal(&sem->cond);
126*7dd7cddfSDavid du Colombier     scode2 = pthread_mutex_unlock(&sem->mutex);
127*7dd7cddfSDavid du Colombier     if (scode == 0)
128*7dd7cddfSDavid du Colombier 	scode = scode2;
129*7dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
130*7dd7cddfSDavid du Colombier }
131*7dd7cddfSDavid du Colombier 
132*7dd7cddfSDavid du Colombier 
133*7dd7cddfSDavid du Colombier /* Monitor supports enter/leave semantics */
134*7dd7cddfSDavid du Colombier 
135*7dd7cddfSDavid du Colombier uint
136*7dd7cddfSDavid du Colombier gp_monitor_sizeof(void)
137*7dd7cddfSDavid du Colombier {
138*7dd7cddfSDavid du Colombier     return sizeof(pthread_mutex_t);
139*7dd7cddfSDavid du Colombier }
140*7dd7cddfSDavid du Colombier 
141*7dd7cddfSDavid du Colombier int
142*7dd7cddfSDavid du Colombier gp_monitor_open(gp_monitor * mona)
143*7dd7cddfSDavid du Colombier {
144*7dd7cddfSDavid du Colombier     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
145*7dd7cddfSDavid du Colombier     int scode;
146*7dd7cddfSDavid du Colombier 
147*7dd7cddfSDavid du Colombier     if (!mona)
148*7dd7cddfSDavid du Colombier 	return -1;		/* monitors are not movable */
149*7dd7cddfSDavid du Colombier     scode = pthread_mutex_init(mon, NULL);
150*7dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
151*7dd7cddfSDavid du Colombier }
152*7dd7cddfSDavid du Colombier 
153*7dd7cddfSDavid du Colombier int
154*7dd7cddfSDavid du Colombier gp_monitor_close(gp_monitor * mona)
155*7dd7cddfSDavid du Colombier {
156*7dd7cddfSDavid du Colombier     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
157*7dd7cddfSDavid du Colombier     int scode;
158*7dd7cddfSDavid du Colombier 
159*7dd7cddfSDavid du Colombier     scode = pthread_mutex_destroy(mon);
160*7dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
161*7dd7cddfSDavid du Colombier }
162*7dd7cddfSDavid du Colombier 
163*7dd7cddfSDavid du Colombier int
164*7dd7cddfSDavid du Colombier gp_monitor_enter(gp_monitor * mona)
165*7dd7cddfSDavid du Colombier {
166*7dd7cddfSDavid du Colombier     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
167*7dd7cddfSDavid du Colombier     int scode;
168*7dd7cddfSDavid du Colombier 
169*7dd7cddfSDavid du Colombier     scode = pthread_mutex_lock(mon);
170*7dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
171*7dd7cddfSDavid du Colombier }
172*7dd7cddfSDavid du Colombier 
173*7dd7cddfSDavid du Colombier int
174*7dd7cddfSDavid du Colombier gp_monitor_leave(gp_monitor * mona)
175*7dd7cddfSDavid du Colombier {
176*7dd7cddfSDavid du Colombier     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
177*7dd7cddfSDavid du Colombier     int scode;
178*7dd7cddfSDavid du Colombier 
179*7dd7cddfSDavid du Colombier     scode = pthread_mutex_unlock(mon);
180*7dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
181*7dd7cddfSDavid du Colombier }
182*7dd7cddfSDavid du Colombier 
183*7dd7cddfSDavid du Colombier 
184*7dd7cddfSDavid du Colombier /* --------- Thread primitives ---------- */
185*7dd7cddfSDavid du Colombier 
186*7dd7cddfSDavid du Colombier /*
187*7dd7cddfSDavid du Colombier  * In order to deal with the type mismatch between our thread API, where
188*7dd7cddfSDavid du Colombier  * the starting procedure returns void, and the API defined by pthreads,
189*7dd7cddfSDavid du Colombier  * where the procedure returns void *, we need to create a wrapper
190*7dd7cddfSDavid du Colombier  * closure.
191*7dd7cddfSDavid du Colombier  */
192*7dd7cddfSDavid du Colombier typedef struct gp_thread_creation_closure_s {
193*7dd7cddfSDavid du Colombier     gp_thread_creation_callback_t proc;  /* actual start procedure */
194*7dd7cddfSDavid du Colombier     void *proc_data;			/* closure data for proc */
195*7dd7cddfSDavid du Colombier } gp_thread_creation_closure_t;
196*7dd7cddfSDavid du Colombier 
197*7dd7cddfSDavid du Colombier /* Wrapper procedure called to start the new thread. */
198*7dd7cddfSDavid du Colombier private void *
199*7dd7cddfSDavid du Colombier gp_thread_begin_wrapper(void *thread_data /* gp_thread_creation_closure_t * */)
200*7dd7cddfSDavid du Colombier {
201*7dd7cddfSDavid du Colombier     gp_thread_creation_closure_t closure;
202*7dd7cddfSDavid du Colombier 
203*7dd7cddfSDavid du Colombier     closure = *(gp_thread_creation_closure_t *)thread_data;
204*7dd7cddfSDavid du Colombier     free(thread_data);
205*7dd7cddfSDavid du Colombier     DISCARD(closure.proc(closure.proc_data));
206*7dd7cddfSDavid du Colombier     return NULL;		/* return value is ignored */
207*7dd7cddfSDavid du Colombier }
208*7dd7cddfSDavid du Colombier 
209*7dd7cddfSDavid du Colombier int
210*7dd7cddfSDavid du Colombier gp_create_thread(gp_thread_creation_callback_t proc, void *proc_data)
211*7dd7cddfSDavid du Colombier {
212*7dd7cddfSDavid du Colombier     gp_thread_creation_closure_t *closure =
213*7dd7cddfSDavid du Colombier 	(gp_thread_creation_closure_t *)malloc(sizeof(*closure));
214*7dd7cddfSDavid du Colombier     pthread_t ignore_thread;
215*7dd7cddfSDavid du Colombier     pthread_attr_t attr;
216*7dd7cddfSDavid du Colombier     int code;
217*7dd7cddfSDavid du Colombier 
218*7dd7cddfSDavid du Colombier     if (!closure)
219*7dd7cddfSDavid du Colombier 	return_error(gs_error_VMerror);
220*7dd7cddfSDavid du Colombier     closure->proc = proc;
221*7dd7cddfSDavid du Colombier     closure->proc_data = proc_data;
222*7dd7cddfSDavid du Colombier     pthread_attr_init(&attr);
223*7dd7cddfSDavid du Colombier     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
224*7dd7cddfSDavid du Colombier     code = pthread_create(&ignore_thread, &attr, gp_thread_begin_wrapper,
225*7dd7cddfSDavid du Colombier 			  closure);
226*7dd7cddfSDavid du Colombier     if (code) {
227*7dd7cddfSDavid du Colombier 	free(closure);
228*7dd7cddfSDavid du Colombier 	return_error(gs_error_ioerror);
229*7dd7cddfSDavid du Colombier     }
230*7dd7cddfSDavid du Colombier     return 0;
231*7dd7cddfSDavid du Colombier }
232