1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: gp_psync.c 8715 2008-05-08 19:10:40Z ray $ */
15
/* POSIX pthreads threads / semaphore / monitor implementation */
24
* Thanks to Larry Jones <larry.jones@sdrc.com> for this revision of
25
* Aladdin's original code into a form that depends only on POSIX APIs.
29
* Some old versions of the pthreads library define
30
* pthread_attr_setdetachstate as taking a Boolean rather than an enum.
31
* Compensate for this here.
33
#ifndef PTHREAD_CREATE_DETACHED
34
# define PTHREAD_CREATE_DETACHED 1
37
/* ------- Synchronization primitives -------- */
39
/* Semaphore supports wait/signal semantics */
41
typedef struct pt_semaphore_t {
43
pthread_mutex_t mutex;
48
gp_semaphore_sizeof(void)
50
return sizeof(pt_semaphore_t);
54
* This procedure should really check errno and return something
55
* more informative....
57
#define SEM_ERROR_CODE(scode)\
58
(scode != 0 ? gs_note_error(gs_error_ioerror) : 0)
61
gp_semaphore_open(gp_semaphore * sema)
63
pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
67
return -1; /* semaphores are not movable */
69
scode = pthread_mutex_init(&sem->mutex, NULL);
71
scode = pthread_cond_init(&sem->cond, NULL);
72
return SEM_ERROR_CODE(scode);
76
gp_semaphore_close(gp_semaphore * sema)
78
pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
81
scode = pthread_cond_destroy(&sem->cond);
82
scode2 = pthread_mutex_destroy(&sem->mutex);
85
return SEM_ERROR_CODE(scode);
89
gp_semaphore_wait(gp_semaphore * sema)
91
pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
94
scode = pthread_mutex_lock(&sem->mutex);
96
return SEM_ERROR_CODE(scode);
97
while (sem->count == 0) {
98
scode = pthread_cond_wait(&sem->cond, &sem->mutex);
104
scode2 = pthread_mutex_unlock(&sem->mutex);
107
return SEM_ERROR_CODE(scode);
111
gp_semaphore_signal(gp_semaphore * sema)
113
pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
116
scode = pthread_mutex_lock(&sem->mutex);
118
return SEM_ERROR_CODE(scode);
119
if (sem->count++ == 0)
120
scode = pthread_cond_signal(&sem->cond);
121
scode2 = pthread_mutex_unlock(&sem->mutex);
124
return SEM_ERROR_CODE(scode);
128
/* Monitor supports enter/leave semantics */
131
* We need PTHREAD_MUTEX_RECURSIVE behavior, but this isn't totally portable
132
* so we implement it in a more portable fashion, keeping track of the
133
* owner thread using 'pthread_self()'
135
typedef struct gp_pthread_recursive_s {
136
pthread_mutex_t mutex; /* actual mutex */
137
pthread_t self_id; /* owner */
138
} gp_pthread_recursive_t;
141
gp_monitor_sizeof(void)
143
return sizeof(gp_pthread_recursive_t);
147
gp_monitor_open(gp_monitor * mona)
149
pthread_mutex_t * const mon = &((gp_pthread_recursive_t *)mona)->mutex;
153
return -1; /* monitors are not movable */
154
((gp_pthread_recursive_t *)mona)->self_id = 0; /* Not valid unless mutex is locked */
155
scode = pthread_mutex_init(mon, NULL);
156
return SEM_ERROR_CODE(scode);
160
gp_monitor_close(gp_monitor * mona)
162
pthread_mutex_t * const mon = &((gp_pthread_recursive_t *)mona)->mutex;
165
scode = pthread_mutex_destroy(mon);
166
return SEM_ERROR_CODE(scode);
170
gp_monitor_enter(gp_monitor * mona)
172
pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
175
if ((scode = pthread_mutex_trylock(mon)) == 0) {
176
((gp_pthread_recursive_t *)mona)->self_id = pthread_self();
177
return SEM_ERROR_CODE(scode);
179
if (pthread_equal(pthread_self(),((gp_pthread_recursive_t *)mona)->self_id))
182
/* we were not the owner, wait */
183
scode = pthread_mutex_lock(mon);
184
((gp_pthread_recursive_t *)mona)->self_id = pthread_self();
185
return SEM_ERROR_CODE(scode);
191
gp_monitor_leave(gp_monitor * mona)
193
pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
196
scode = pthread_mutex_unlock(mon);
197
((gp_pthread_recursive_t *)mona)->self_id = 0; /* Not valid unless mutex is locked */
198
return SEM_ERROR_CODE(scode);
202
/* --------- Thread primitives ---------- */
205
* In order to deal with the type mismatch between our thread API, where
206
* the starting procedure returns void, and the API defined by pthreads,
207
* where the procedure returns void *, we need to create a wrapper
210
typedef struct gp_thread_creation_closure_s {
211
gp_thread_creation_callback_t proc; /* actual start procedure */
212
void *proc_data; /* closure data for proc */
213
} gp_thread_creation_closure_t;
215
/* Wrapper procedure called to start the new thread. */
217
gp_thread_begin_wrapper(void *thread_data /* gp_thread_creation_closure_t * */)
219
gp_thread_creation_closure_t closure;
221
closure = *(gp_thread_creation_closure_t *)thread_data;
223
DISCARD(closure.proc(closure.proc_data));
224
return NULL; /* return value is ignored */
228
gp_create_thread(gp_thread_creation_callback_t proc, void *proc_data)
230
gp_thread_creation_closure_t *closure =
231
(gp_thread_creation_closure_t *)malloc(sizeof(*closure));
232
pthread_t ignore_thread;
237
return_error(gs_error_VMerror);
238
closure->proc = proc;
239
closure->proc_data = proc_data;
240
pthread_attr_init(&attr);
241
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
242
code = pthread_create(&ignore_thread, &attr, gp_thread_begin_wrapper,
246
return_error(gs_error_ioerror);