2 |
- |
1 |
/* Copyright (C) 1999 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_wsync.c,v 1.4 2002/02/21 22:24:52 giles Exp $ */
|
|
|
18 |
/* MS Windows (Win32) thread / semaphore / monitor implementation */
|
|
|
19 |
/* original multi-threading code by John Desrosiers */
|
|
|
20 |
#include "malloc_.h"
|
|
|
21 |
#include "gserror.h"
|
|
|
22 |
#include "gserrors.h"
|
|
|
23 |
#include "gpsync.h"
|
|
|
24 |
#include "windows_.h"
|
|
|
25 |
#include <process.h>
|
|
|
26 |
|
|
|
27 |
/* ------- Synchronization primitives -------- */
|
|
|
28 |
|
|
|
29 |
/* Semaphore supports wait/signal semantics */
|
|
|
30 |
|
|
|
31 |
typedef struct win32_semaphore_s {
|
|
|
32 |
HANDLE handle; /* returned from CreateSemaphore */
|
|
|
33 |
} win32_semaphore;
|
|
|
34 |
|
|
|
35 |
uint
|
|
|
36 |
gp_semaphore_sizeof(void)
|
|
|
37 |
{
|
|
|
38 |
return sizeof(win32_semaphore);
|
|
|
39 |
}
|
|
|
40 |
|
|
|
41 |
int /* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */
|
|
|
42 |
gp_semaphore_open(
|
|
|
43 |
gp_semaphore * sema /* create semaphore here */
|
|
|
44 |
)
|
|
|
45 |
{
|
|
|
46 |
win32_semaphore *const winSema = (win32_semaphore *)sema;
|
|
|
47 |
|
|
|
48 |
if (winSema) {
|
|
|
49 |
winSema->handle = CreateSemaphore(NULL, 0, max_int, NULL);
|
|
|
50 |
return
|
|
|
51 |
(winSema->handle != NULL ? 0 :
|
|
|
52 |
gs_note_error(gs_error_unknownerror));
|
|
|
53 |
} else
|
|
|
54 |
return 0; /* Win32 semaphores handles may be moved */
|
|
|
55 |
}
|
|
|
56 |
|
|
|
57 |
int
|
|
|
58 |
gp_semaphore_close(
|
|
|
59 |
gp_semaphore * sema /* semaphore to affect */
|
|
|
60 |
)
|
|
|
61 |
{
|
|
|
62 |
win32_semaphore *const winSema = (win32_semaphore *)sema;
|
|
|
63 |
|
|
|
64 |
if (winSema->handle != NULL)
|
|
|
65 |
CloseHandle(winSema->handle);
|
|
|
66 |
winSema->handle = NULL;
|
|
|
67 |
return 0;
|
|
|
68 |
}
|
|
|
69 |
|
|
|
70 |
int /* rets 0 ok, -ve error */
|
|
|
71 |
gp_semaphore_wait(
|
|
|
72 |
gp_semaphore * sema /* semaphore to affect */
|
|
|
73 |
)
|
|
|
74 |
{
|
|
|
75 |
win32_semaphore *const winSema = (win32_semaphore *)sema;
|
|
|
76 |
|
|
|
77 |
return
|
|
|
78 |
(WaitForSingleObject(winSema->handle, INFINITE) == WAIT_OBJECT_0
|
|
|
79 |
? 0 : gs_error_unknownerror);
|
|
|
80 |
}
|
|
|
81 |
|
|
|
82 |
int /* rets 0 ok, -ve error */
|
|
|
83 |
gp_semaphore_signal(
|
|
|
84 |
gp_semaphore * sema /* semaphore to affect */
|
|
|
85 |
)
|
|
|
86 |
{
|
|
|
87 |
win32_semaphore *const winSema = (win32_semaphore *)sema;
|
|
|
88 |
|
|
|
89 |
return
|
|
|
90 |
(ReleaseSemaphore(winSema->handle, 1, NULL) ? 0 :
|
|
|
91 |
gs_error_unknownerror);
|
|
|
92 |
}
|
|
|
93 |
|
|
|
94 |
|
|
|
95 |
/* Monitor supports enter/leave semantics */
|
|
|
96 |
|
|
|
97 |
typedef struct win32_monitor_s {
|
|
|
98 |
CRITICAL_SECTION lock; /* critical section lock */
|
|
|
99 |
} win32_monitor;
|
|
|
100 |
|
|
|
101 |
uint
|
|
|
102 |
gp_monitor_sizeof(void)
|
|
|
103 |
{
|
|
|
104 |
return sizeof(win32_monitor);
|
|
|
105 |
}
|
|
|
106 |
|
|
|
107 |
int /* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */
|
|
|
108 |
gp_monitor_open(
|
|
|
109 |
gp_monitor * mon /* create monitor here */
|
|
|
110 |
)
|
|
|
111 |
{
|
|
|
112 |
win32_monitor *const winMon = (win32_monitor *)mon;
|
|
|
113 |
|
|
|
114 |
if (mon) {
|
|
|
115 |
InitializeCriticalSection(&winMon->lock); /* returns no status */
|
|
|
116 |
return 0;
|
|
|
117 |
} else
|
|
|
118 |
return 1; /* Win32 critical sections mutsn't be moved */
|
|
|
119 |
}
|
|
|
120 |
|
|
|
121 |
int
|
|
|
122 |
gp_monitor_close(
|
|
|
123 |
gp_monitor * mon /* monitor to affect */
|
|
|
124 |
)
|
|
|
125 |
{
|
|
|
126 |
win32_monitor *const winMon = (win32_monitor *)mon;
|
|
|
127 |
|
|
|
128 |
DeleteCriticalSection(&winMon->lock); /* rets no status */
|
|
|
129 |
return 0;
|
|
|
130 |
}
|
|
|
131 |
|
|
|
132 |
int /* rets 0 ok, -ve error */
|
|
|
133 |
gp_monitor_enter(
|
|
|
134 |
gp_monitor * mon /* monitor to affect */
|
|
|
135 |
)
|
|
|
136 |
{
|
|
|
137 |
win32_monitor *const winMon = (win32_monitor *)mon;
|
|
|
138 |
|
|
|
139 |
EnterCriticalSection(&winMon->lock); /* rets no status */
|
|
|
140 |
return 0;
|
|
|
141 |
}
|
|
|
142 |
|
|
|
143 |
int /* rets 0 ok, -ve error */
|
|
|
144 |
gp_monitor_leave(
|
|
|
145 |
gp_monitor * mon /* monitor to affect */
|
|
|
146 |
)
|
|
|
147 |
{
|
|
|
148 |
win32_monitor *const winMon = (win32_monitor *)mon;
|
|
|
149 |
|
|
|
150 |
LeaveCriticalSection(&winMon->lock); /* rets no status */
|
|
|
151 |
return 0;
|
|
|
152 |
}
|
|
|
153 |
|
|
|
154 |
/* --------- Thread primitives ---------- */
|
|
|
155 |
|
|
|
156 |
typedef struct gp_thread_creation_closure_s {
|
|
|
157 |
gp_thread_creation_callback_t function; /* function to start */
|
|
|
158 |
void *data; /* magic data to pass to thread */
|
|
|
159 |
} gp_thread_creation_closure;
|
|
|
160 |
|
|
|
161 |
/* Origin of new threads started by gp_create_thread */
|
|
|
162 |
private void
|
|
|
163 |
gp_thread_begin_wrapper(
|
|
|
164 |
void *thread_data /* gp_thread_creation_closure passed as magic data */
|
|
|
165 |
)
|
|
|
166 |
{
|
|
|
167 |
gp_thread_creation_closure closure;
|
|
|
168 |
|
|
|
169 |
closure = *(gp_thread_creation_closure *)thread_data;
|
|
|
170 |
free(thread_data);
|
|
|
171 |
(*closure.function)(closure.data);
|
|
|
172 |
_endthread();
|
|
|
173 |
}
|
|
|
174 |
|
|
|
175 |
/* Call a function on a brand new thread */
|
|
|
176 |
int /* 0 ok, -ve error */
|
|
|
177 |
gp_create_thread(
|
|
|
178 |
gp_thread_creation_callback_t function, /* function to start */
|
|
|
179 |
void *data /* magic data to pass to thread fn */
|
|
|
180 |
)
|
|
|
181 |
{
|
|
|
182 |
/* Create the magic closure that thread_wrapper gets passed */
|
|
|
183 |
gp_thread_creation_closure *closure =
|
|
|
184 |
(gp_thread_creation_closure *)malloc(sizeof(*closure));
|
|
|
185 |
|
|
|
186 |
if (!closure)
|
|
|
187 |
return gs_error_VMerror;
|
|
|
188 |
closure->function = function;
|
|
|
189 |
closure->data = data;
|
|
|
190 |
|
|
|
191 |
/*
|
|
|
192 |
* Start thread_wrapper. The Watcom _beginthread returns (int)(-1) if
|
|
|
193 |
* the call fails. The Microsoft _beginthread returns -1 (according to
|
|
|
194 |
* the doc, even though the return type is "unsigned long" !!!) if the
|
|
|
195 |
* call fails; we aren't sure what the Borland _beginthread returns.
|
|
|
196 |
* The hack with ~ avoids a source code commitment as to whether the
|
|
|
197 |
* return type is [u]int or [u]long.
|
|
|
198 |
*
|
|
|
199 |
* BEGIN_THREAD is a macro (defined in windows_.h) because _beginthread
|
|
|
200 |
* takes different arguments in Watcom C.
|
|
|
201 |
*/
|
|
|
202 |
if (~BEGIN_THREAD(gp_thread_begin_wrapper, 0, closure) != 0)
|
|
|
203 |
return 0;
|
|
|
204 |
return_error(gs_error_unknownerror);
|
|
|
205 |
}
|
|
|
206 |
|