1 /* Copyright (C) 1999, 2000 Aladdin Enterprises. All rights reserved. 2 3 This software is provided AS-IS with no warranty, either express or 4 implied. 5 6 This software is distributed under license and may not be copied, 7 modified or distributed except as expressly authorized under the terms 8 of the license contained in the file LICENSE in this distribution. 9 10 For more information about licensing, please refer to 11 http://www.ghostscript.com/licensing/. For information on 12 commercial licensing, go to http://www.artifex.com/licensing/ or 13 contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14 San Rafael, CA 94903, U.S.A., +1(415)492-9861. 15 */ 16 17 /* $Id: gp_psync.c,v 1.4 2002/02/21 22:24:52 giles Exp $ */ 18 /* POSIX pthreads threads / semaphore / monitor implementation */ 19 #include "std.h" 20 #include "malloc_.h" 21 #include <pthread.h> 22 #include "gserror.h" 23 #include "gserrors.h" 24 #include "gpsync.h" 25 26 /* 27 * Thanks to Larry Jones <larry.jones@sdrc.com> for this revision of 28 * Aladdin's original code into a form that depends only on POSIX APIs. 29 */ 30 31 /* 32 * Some old versions of the pthreads library define 33 * pthread_attr_setdetachstate as taking a Boolean rather than an enum. 34 * Compensate for this here. 35 */ 36 #ifndef PTHREAD_CREATE_DETACHED 37 # define PTHREAD_CREATE_DETACHED 1 38 #endif 39 40 /* ------- Synchronization primitives -------- */ 41 42 /* Semaphore supports wait/signal semantics */ 43 44 typedef struct pt_semaphore_t { 45 int count; 46 pthread_mutex_t mutex; 47 pthread_cond_t cond; 48 } pt_semaphore_t; 49 50 uint 51 gp_semaphore_sizeof(void) 52 { 53 return sizeof(pt_semaphore_t); 54 } 55 56 /* 57 * This procedure should really check errno and return something 58 * more informative.... 59 */ 60 #define SEM_ERROR_CODE(scode)\ 61 (scode != 0 ? gs_note_error(gs_error_ioerror) : 0) 62 63 int 64 gp_semaphore_open(gp_semaphore * sema) 65 { 66 pt_semaphore_t * const sem = (pt_semaphore_t *)sema; 67 int scode; 68 69 if (!sema) 70 return -1; /* semaphores are not movable */ 71 sem->count = 0; 72 scode = pthread_mutex_init(&sem->mutex, NULL); 73 if (scode == 0) 74 scode = pthread_cond_init(&sem->cond, NULL); 75 return SEM_ERROR_CODE(scode); 76 } 77 78 int 79 gp_semaphore_close(gp_semaphore * sema) 80 { 81 pt_semaphore_t * const sem = (pt_semaphore_t *)sema; 82 int scode, scode2; 83 84 scode = pthread_cond_destroy(&sem->cond); 85 scode2 = pthread_mutex_destroy(&sem->mutex); 86 if (scode == 0) 87 scode = scode2; 88 return SEM_ERROR_CODE(scode); 89 } 90 91 int 92 gp_semaphore_wait(gp_semaphore * sema) 93 { 94 pt_semaphore_t * const sem = (pt_semaphore_t *)sema; 95 int scode, scode2; 96 97 scode = pthread_mutex_lock(&sem->mutex); 98 if (scode != 0) 99 return SEM_ERROR_CODE(scode); 100 while (sem->count == 0) { 101 scode = pthread_cond_wait(&sem->cond, &sem->mutex); 102 if (scode != 0) 103 break; 104 } 105 if (scode == 0) 106 --sem->count; 107 scode2 = pthread_mutex_unlock(&sem->mutex); 108 if (scode == 0) 109 scode = scode2; 110 return SEM_ERROR_CODE(scode); 111 } 112 113 int 114 gp_semaphore_signal(gp_semaphore * sema) 115 { 116 pt_semaphore_t * const sem = (pt_semaphore_t *)sema; 117 int scode, scode2; 118 119 scode = pthread_mutex_lock(&sem->mutex); 120 if (scode != 0) 121 return SEM_ERROR_CODE(scode); 122 if (sem->count++ == 0) 123 scode = pthread_cond_signal(&sem->cond); 124 scode2 = pthread_mutex_unlock(&sem->mutex); 125 if (scode == 0) 126 scode = scode2; 127 return SEM_ERROR_CODE(scode); 128 } 129 130 131 /* Monitor supports enter/leave semantics */ 132 133 uint 134 gp_monitor_sizeof(void) 135 { 136 return sizeof(pthread_mutex_t); 137 } 138 139 int 140 gp_monitor_open(gp_monitor * mona) 141 { 142 pthread_mutex_t * const mon = (pthread_mutex_t *)mona; 143 int scode; 144 145 if (!mona) 146 return -1; /* monitors are not movable */ 147 scode = pthread_mutex_init(mon, NULL); 148 return SEM_ERROR_CODE(scode); 149 } 150 151 int 152 gp_monitor_close(gp_monitor * mona) 153 { 154 pthread_mutex_t * const mon = (pthread_mutex_t *)mona; 155 int scode; 156 157 scode = pthread_mutex_destroy(mon); 158 return SEM_ERROR_CODE(scode); 159 } 160 161 int 162 gp_monitor_enter(gp_monitor * mona) 163 { 164 pthread_mutex_t * const mon = (pthread_mutex_t *)mona; 165 int scode; 166 167 scode = pthread_mutex_lock(mon); 168 return SEM_ERROR_CODE(scode); 169 } 170 171 int 172 gp_monitor_leave(gp_monitor * mona) 173 { 174 pthread_mutex_t * const mon = (pthread_mutex_t *)mona; 175 int scode; 176 177 scode = pthread_mutex_unlock(mon); 178 return SEM_ERROR_CODE(scode); 179 } 180 181 182 /* --------- Thread primitives ---------- */ 183 184 /* 185 * In order to deal with the type mismatch between our thread API, where 186 * the starting procedure returns void, and the API defined by pthreads, 187 * where the procedure returns void *, we need to create a wrapper 188 * closure. 189 */ 190 typedef struct gp_thread_creation_closure_s { 191 gp_thread_creation_callback_t proc; /* actual start procedure */ 192 void *proc_data; /* closure data for proc */ 193 } gp_thread_creation_closure_t; 194 195 /* Wrapper procedure called to start the new thread. */ 196 private void * 197 gp_thread_begin_wrapper(void *thread_data /* gp_thread_creation_closure_t * */) 198 { 199 gp_thread_creation_closure_t closure; 200 201 closure = *(gp_thread_creation_closure_t *)thread_data; 202 free(thread_data); 203 DISCARD(closure.proc(closure.proc_data)); 204 return NULL; /* return value is ignored */ 205 } 206 207 int 208 gp_create_thread(gp_thread_creation_callback_t proc, void *proc_data) 209 { 210 gp_thread_creation_closure_t *closure = 211 (gp_thread_creation_closure_t *)malloc(sizeof(*closure)); 212 pthread_t ignore_thread; 213 pthread_attr_t attr; 214 int code; 215 216 if (!closure) 217 return_error(gs_error_VMerror); 218 closure->proc = proc; 219 closure->proc_data = proc_data; 220 pthread_attr_init(&attr); 221 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 222 code = pthread_create(&ignore_thread, &attr, gp_thread_begin_wrapper, 223 closure); 224 if (code) { 225 free(closure); 226 return_error(gs_error_ioerror); 227 } 228 return 0; 229 } 230