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