xref: /plan9/sys/src/cmd/gs/src/gp_wsync.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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
gp_semaphore_sizeof(void)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 */
gp_semaphore_open(gp_semaphore * sema)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
gp_semaphore_close(gp_semaphore * sema)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 */
gp_semaphore_wait(gp_semaphore * sema)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 */
gp_semaphore_signal(gp_semaphore * sema)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
gp_monitor_sizeof(void)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 */
gp_monitor_open(gp_monitor * mon)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
gp_monitor_close(gp_monitor * mon)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 */
gp_monitor_enter(gp_monitor * mon)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 */
gp_monitor_leave(gp_monitor * mon)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
gp_thread_begin_wrapper(void * thread_data)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 */
gp_create_thread(gp_thread_creation_callback_t function,void * data)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 
207