xref: /plan9/sys/src/cmd/gs/src/gp_psync.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1999, 2000 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gp_psync.c,v 1.4 2002/02/21 22:24:52 giles Exp $ */
187dd7cddfSDavid du Colombier /* POSIX pthreads threads / semaphore / monitor implementation */
197dd7cddfSDavid du Colombier #include "std.h"
207dd7cddfSDavid du Colombier #include "malloc_.h"
217dd7cddfSDavid du Colombier #include <pthread.h>
227dd7cddfSDavid du Colombier #include "gserror.h"
237dd7cddfSDavid du Colombier #include "gserrors.h"
247dd7cddfSDavid du Colombier #include "gpsync.h"
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier /*
277dd7cddfSDavid du Colombier  * Thanks to Larry Jones <larry.jones@sdrc.com> for this revision of
287dd7cddfSDavid du Colombier  * Aladdin's original code into a form that depends only on POSIX APIs.
297dd7cddfSDavid du Colombier  */
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier /*
327dd7cddfSDavid du Colombier  * Some old versions of the pthreads library define
337dd7cddfSDavid du Colombier  * pthread_attr_setdetachstate as taking a Boolean rather than an enum.
347dd7cddfSDavid du Colombier  * Compensate for this here.
357dd7cddfSDavid du Colombier  */
367dd7cddfSDavid du Colombier #ifndef PTHREAD_CREATE_DETACHED
377dd7cddfSDavid du Colombier #  define PTHREAD_CREATE_DETACHED 1
387dd7cddfSDavid du Colombier #endif
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier /* ------- Synchronization primitives -------- */
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier /* Semaphore supports wait/signal semantics */
437dd7cddfSDavid du Colombier 
447dd7cddfSDavid du Colombier typedef struct pt_semaphore_t {
457dd7cddfSDavid du Colombier     int count;
467dd7cddfSDavid du Colombier     pthread_mutex_t mutex;
477dd7cddfSDavid du Colombier     pthread_cond_t cond;
487dd7cddfSDavid du Colombier } pt_semaphore_t;
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier uint
gp_semaphore_sizeof(void)517dd7cddfSDavid du Colombier gp_semaphore_sizeof(void)
527dd7cddfSDavid du Colombier {
537dd7cddfSDavid du Colombier     return sizeof(pt_semaphore_t);
547dd7cddfSDavid du Colombier }
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier /*
577dd7cddfSDavid du Colombier  * This procedure should really check errno and return something
587dd7cddfSDavid du Colombier  * more informative....
597dd7cddfSDavid du Colombier  */
607dd7cddfSDavid du Colombier #define SEM_ERROR_CODE(scode)\
617dd7cddfSDavid du Colombier   (scode != 0 ? gs_note_error(gs_error_ioerror) : 0)
627dd7cddfSDavid du Colombier 
637dd7cddfSDavid du Colombier int
gp_semaphore_open(gp_semaphore * sema)647dd7cddfSDavid du Colombier gp_semaphore_open(gp_semaphore * sema)
657dd7cddfSDavid du Colombier {
667dd7cddfSDavid du Colombier     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
677dd7cddfSDavid du Colombier     int scode;
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier     if (!sema)
707dd7cddfSDavid du Colombier 	return -1;		/* semaphores are not movable */
717dd7cddfSDavid du Colombier     sem->count = 0;
727dd7cddfSDavid du Colombier     scode = pthread_mutex_init(&sem->mutex, NULL);
737dd7cddfSDavid du Colombier     if (scode == 0)
747dd7cddfSDavid du Colombier 	scode = pthread_cond_init(&sem->cond, NULL);
757dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
767dd7cddfSDavid du Colombier }
777dd7cddfSDavid du Colombier 
787dd7cddfSDavid du Colombier int
gp_semaphore_close(gp_semaphore * sema)797dd7cddfSDavid du Colombier gp_semaphore_close(gp_semaphore * sema)
807dd7cddfSDavid du Colombier {
817dd7cddfSDavid du Colombier     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
827dd7cddfSDavid du Colombier     int scode, scode2;
837dd7cddfSDavid du Colombier 
847dd7cddfSDavid du Colombier     scode = pthread_cond_destroy(&sem->cond);
857dd7cddfSDavid du Colombier     scode2 = pthread_mutex_destroy(&sem->mutex);
867dd7cddfSDavid du Colombier     if (scode == 0)
877dd7cddfSDavid du Colombier 	scode = scode2;
887dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
897dd7cddfSDavid du Colombier }
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier int
gp_semaphore_wait(gp_semaphore * sema)927dd7cddfSDavid du Colombier gp_semaphore_wait(gp_semaphore * sema)
937dd7cddfSDavid du Colombier {
947dd7cddfSDavid du Colombier     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
957dd7cddfSDavid du Colombier     int scode, scode2;
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier     scode = pthread_mutex_lock(&sem->mutex);
987dd7cddfSDavid du Colombier     if (scode != 0)
997dd7cddfSDavid du Colombier 	return SEM_ERROR_CODE(scode);
1007dd7cddfSDavid du Colombier     while (sem->count == 0) {
1017dd7cddfSDavid du Colombier         scode = pthread_cond_wait(&sem->cond, &sem->mutex);
1027dd7cddfSDavid du Colombier         if (scode != 0)
1037dd7cddfSDavid du Colombier 	    break;
1047dd7cddfSDavid du Colombier     }
1057dd7cddfSDavid du Colombier     if (scode == 0)
1067dd7cddfSDavid du Colombier 	--sem->count;
1077dd7cddfSDavid du Colombier     scode2 = pthread_mutex_unlock(&sem->mutex);
1087dd7cddfSDavid du Colombier     if (scode == 0)
1097dd7cddfSDavid du Colombier 	scode = scode2;
1107dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
1117dd7cddfSDavid du Colombier }
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier int
gp_semaphore_signal(gp_semaphore * sema)1147dd7cddfSDavid du Colombier gp_semaphore_signal(gp_semaphore * sema)
1157dd7cddfSDavid du Colombier {
1167dd7cddfSDavid du Colombier     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
1177dd7cddfSDavid du Colombier     int scode, scode2;
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier     scode = pthread_mutex_lock(&sem->mutex);
1207dd7cddfSDavid du Colombier     if (scode != 0)
1217dd7cddfSDavid du Colombier 	return SEM_ERROR_CODE(scode);
1227dd7cddfSDavid du Colombier     if (sem->count++ == 0)
1237dd7cddfSDavid du Colombier 	scode = pthread_cond_signal(&sem->cond);
1247dd7cddfSDavid du Colombier     scode2 = pthread_mutex_unlock(&sem->mutex);
1257dd7cddfSDavid du Colombier     if (scode == 0)
1267dd7cddfSDavid du Colombier 	scode = scode2;
1277dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
1287dd7cddfSDavid du Colombier }
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier /* Monitor supports enter/leave semantics */
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier uint
gp_monitor_sizeof(void)1347dd7cddfSDavid du Colombier gp_monitor_sizeof(void)
1357dd7cddfSDavid du Colombier {
1367dd7cddfSDavid du Colombier     return sizeof(pthread_mutex_t);
1377dd7cddfSDavid du Colombier }
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier int
gp_monitor_open(gp_monitor * mona)1407dd7cddfSDavid du Colombier gp_monitor_open(gp_monitor * mona)
1417dd7cddfSDavid du Colombier {
1427dd7cddfSDavid du Colombier     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
1437dd7cddfSDavid du Colombier     int scode;
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier     if (!mona)
1467dd7cddfSDavid du Colombier 	return -1;		/* monitors are not movable */
1477dd7cddfSDavid du Colombier     scode = pthread_mutex_init(mon, NULL);
1487dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
1497dd7cddfSDavid du Colombier }
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier int
gp_monitor_close(gp_monitor * mona)1527dd7cddfSDavid du Colombier gp_monitor_close(gp_monitor * mona)
1537dd7cddfSDavid du Colombier {
1547dd7cddfSDavid du Colombier     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
1557dd7cddfSDavid du Colombier     int scode;
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier     scode = pthread_mutex_destroy(mon);
1587dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
1597dd7cddfSDavid du Colombier }
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier int
gp_monitor_enter(gp_monitor * mona)1627dd7cddfSDavid du Colombier gp_monitor_enter(gp_monitor * mona)
1637dd7cddfSDavid du Colombier {
1647dd7cddfSDavid du Colombier     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
1657dd7cddfSDavid du Colombier     int scode;
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier     scode = pthread_mutex_lock(mon);
1687dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
1697dd7cddfSDavid du Colombier }
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier int
gp_monitor_leave(gp_monitor * mona)1727dd7cddfSDavid du Colombier gp_monitor_leave(gp_monitor * mona)
1737dd7cddfSDavid du Colombier {
1747dd7cddfSDavid du Colombier     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
1757dd7cddfSDavid du Colombier     int scode;
1767dd7cddfSDavid du Colombier 
1777dd7cddfSDavid du Colombier     scode = pthread_mutex_unlock(mon);
1787dd7cddfSDavid du Colombier     return SEM_ERROR_CODE(scode);
1797dd7cddfSDavid du Colombier }
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier /* --------- Thread primitives ---------- */
1837dd7cddfSDavid du Colombier 
1847dd7cddfSDavid du Colombier /*
1857dd7cddfSDavid du Colombier  * In order to deal with the type mismatch between our thread API, where
1867dd7cddfSDavid du Colombier  * the starting procedure returns void, and the API defined by pthreads,
1877dd7cddfSDavid du Colombier  * where the procedure returns void *, we need to create a wrapper
1887dd7cddfSDavid du Colombier  * closure.
1897dd7cddfSDavid du Colombier  */
1907dd7cddfSDavid du Colombier typedef struct gp_thread_creation_closure_s {
1917dd7cddfSDavid du Colombier     gp_thread_creation_callback_t proc;  /* actual start procedure */
1927dd7cddfSDavid du Colombier     void *proc_data;			/* closure data for proc */
1937dd7cddfSDavid du Colombier } gp_thread_creation_closure_t;
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier /* Wrapper procedure called to start the new thread. */
1967dd7cddfSDavid du Colombier private void *
gp_thread_begin_wrapper(void * thread_data)1977dd7cddfSDavid du Colombier gp_thread_begin_wrapper(void *thread_data /* gp_thread_creation_closure_t * */)
1987dd7cddfSDavid du Colombier {
1997dd7cddfSDavid du Colombier     gp_thread_creation_closure_t closure;
2007dd7cddfSDavid du Colombier 
2017dd7cddfSDavid du Colombier     closure = *(gp_thread_creation_closure_t *)thread_data;
2027dd7cddfSDavid du Colombier     free(thread_data);
2037dd7cddfSDavid du Colombier     DISCARD(closure.proc(closure.proc_data));
2047dd7cddfSDavid du Colombier     return NULL;		/* return value is ignored */
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier int
gp_create_thread(gp_thread_creation_callback_t proc,void * proc_data)2087dd7cddfSDavid du Colombier gp_create_thread(gp_thread_creation_callback_t proc, void *proc_data)
2097dd7cddfSDavid du Colombier {
2107dd7cddfSDavid du Colombier     gp_thread_creation_closure_t *closure =
2117dd7cddfSDavid du Colombier 	(gp_thread_creation_closure_t *)malloc(sizeof(*closure));
2127dd7cddfSDavid du Colombier     pthread_t ignore_thread;
2137dd7cddfSDavid du Colombier     pthread_attr_t attr;
2147dd7cddfSDavid du Colombier     int code;
2157dd7cddfSDavid du Colombier 
2167dd7cddfSDavid du Colombier     if (!closure)
2177dd7cddfSDavid du Colombier 	return_error(gs_error_VMerror);
2187dd7cddfSDavid du Colombier     closure->proc = proc;
2197dd7cddfSDavid du Colombier     closure->proc_data = proc_data;
2207dd7cddfSDavid du Colombier     pthread_attr_init(&attr);
2217dd7cddfSDavid du Colombier     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2227dd7cddfSDavid du Colombier     code = pthread_create(&ignore_thread, &attr, gp_thread_begin_wrapper,
2237dd7cddfSDavid du Colombier 			  closure);
2247dd7cddfSDavid du Colombier     if (code) {
2257dd7cddfSDavid du Colombier 	free(closure);
2267dd7cddfSDavid du Colombier 	return_error(gs_error_ioerror);
2277dd7cddfSDavid du Colombier     }
2287dd7cddfSDavid du Colombier     return 0;
2297dd7cddfSDavid du Colombier }
230