2 |
- |
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 |
}
|