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