copying the latest Sys.Web.Services from trunk.
[mono.git] / mono / io-layer / semaphores.c
1 /*
2  * semaphores.c:  Semaphore handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #ifdef HAVE_SEMAPHORE_H
14 #include <semaphore.h>
15 #endif
16 #include <errno.h>
17 #include <string.h>
18 #include <sys/time.h>
19
20 #include <mono/io-layer/wapi.h>
21 #include <mono/io-layer/wapi-private.h>
22 #include <mono/io-layer/misc-private.h>
23 #include <mono/io-layer/handles-private.h>
24 #include <mono/io-layer/mono-mutex.h>
25 #include <mono/io-layer/semaphore-private.h>
26
27 #undef DEBUG
28
29 static void sema_signal(gpointer handle);
30 static gboolean sema_own (gpointer handle);
31
32 struct _WapiHandleOps _wapi_sem_ops = {
33         NULL,                   /* close */
34         sema_signal,            /* signal */
35         sema_own,               /* own */
36         NULL,                   /* is_owned */
37 };
38
39 void _wapi_sem_details (gpointer handle_info)
40 {
41         struct _WapiHandle_sem *sem = (struct _WapiHandle_sem *)handle_info;
42         
43         g_print ("val: %5u, max: %5d", sem->val, sem->max);
44 }
45
46 static mono_once_t sem_ops_once=MONO_ONCE_INIT;
47
48 static void sem_ops_init (void)
49 {
50         _wapi_handle_register_capabilities (WAPI_HANDLE_SEM,
51                                             WAPI_HANDLE_CAP_WAIT |
52                                             WAPI_HANDLE_CAP_SIGNAL);
53 }
54
55 static void sema_signal(gpointer handle)
56 {
57         ReleaseSemaphore(handle, 1, NULL);
58 }
59
60 static gboolean sema_own (gpointer handle)
61 {
62         struct _WapiHandle_sem *sem_handle;
63         gboolean ok;
64         
65         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_SEM,
66                                 (gpointer *)&sem_handle);
67         if(ok==FALSE) {
68                 g_warning ("%s: error looking up sem handle %p", __func__,
69                            handle);
70                 return(FALSE);
71         }
72         
73 #ifdef DEBUG
74         g_message("%s: owning sem handle %p", __func__, handle);
75 #endif
76
77         sem_handle->val--;
78         
79 #ifdef DEBUG
80         g_message ("%s: sem %p val now %d", __func__, handle, sem_handle->val);
81 #endif
82
83         if(sem_handle->val==0) {
84                 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
85         }
86
87         return(TRUE);
88 }
89
90
91 /**
92  * CreateSemaphore:
93  * @security: Ignored for now.
94  * @initial: The initial count for the semaphore.  The value must be
95  * greater than or equal to zero, and less than or equal to @max.
96  * @max: The maximum count for this semaphore.  The value must be
97  * greater than zero.
98  * @name: Pointer to a string specifying the name of this semaphore,
99  * or %NULL.  Currently ignored.
100  *
101  * Creates a new semaphore handle.  A semaphore is signalled when its
102  * count is greater than zero, and unsignalled otherwise.  The count
103  * is decreased by one whenever a wait function releases a thread that
104  * was waiting for the semaphore.  The count is increased by calling
105  * ReleaseSemaphore().
106  *
107  * Return value: a new handle, or NULL
108  */
109 gpointer CreateSemaphore(WapiSecurityAttributes *security G_GNUC_UNUSED, gint32 initial, gint32 max, const gunichar2 *name G_GNUC_UNUSED)
110 {
111         struct _WapiHandle_sem sem_handle = {0};
112         gpointer handle;
113         int thr_ret;
114         
115         mono_once (&sem_ops_once, sem_ops_init);
116         
117         if(max<=0) {
118 #ifdef DEBUG
119                 g_message("%s: max <= 0", __func__);
120 #endif
121
122                 SetLastError (ERROR_INVALID_PARAMETER);
123                 return(NULL);
124         }
125         
126         if(initial>max || initial<0) {
127 #ifdef DEBUG
128                 g_message("%s: initial>max or < 0", __func__);
129 #endif
130
131                 SetLastError (ERROR_INVALID_PARAMETER);
132                 return(NULL);
133         }
134         
135         sem_handle.val = initial;
136         sem_handle.max = max;
137
138         handle = _wapi_handle_new (WAPI_HANDLE_SEM, &sem_handle);
139         if (handle == _WAPI_HANDLE_INVALID) {
140                 g_warning ("%s: error creating semaphore handle", __func__);
141                 SetLastError (ERROR_GEN_FAILURE);
142                 return(NULL);
143         }
144
145         pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
146                               handle);
147         thr_ret = _wapi_handle_lock_handle (handle);
148         g_assert (thr_ret == 0);
149         
150         if (initial != 0) {
151                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
152         }
153
154 #ifdef DEBUG
155         g_message ("%s: Created semaphore handle %p initial %d max %d",
156                    __func__, handle, initial, max);
157 #endif
158
159         thr_ret = _wapi_handle_unlock_handle (handle);
160         g_assert (thr_ret == 0);
161         pthread_cleanup_pop (0);
162
163         return(handle);
164 }
165
166 /**
167  * ReleaseSemaphore:
168  * @handle: The semaphore handle to release.
169  * @count: The amount by which the semaphore's count should be
170  * increased.
171  * @prevcount: Pointer to a location to store the previous count of
172  * the semaphore, or %NULL.
173  *
174  * Increases the count of semaphore @handle by @count.
175  *
176  * Return value: %TRUE on success, %FALSE otherwise.
177  */
178 gboolean ReleaseSemaphore(gpointer handle, gint32 count, gint32 *prevcount)
179 {
180         struct _WapiHandle_sem *sem_handle;
181         gboolean ok;
182         gboolean ret=FALSE;
183         int thr_ret;
184         
185         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_SEM,
186                                 (gpointer *)&sem_handle);
187         if(ok==FALSE) {
188                 g_warning ("%s: error looking up sem handle %p", __func__,
189                            handle);
190                 return(FALSE);
191         }
192
193         pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
194                               handle);
195         thr_ret = _wapi_handle_lock_handle (handle);
196         g_assert (thr_ret == 0);
197
198 #ifdef DEBUG
199         g_message("%s: sem %p val %d count %d", __func__, handle,
200                   sem_handle->val, count);
201 #endif
202         
203         /* Do this before checking for count overflow, because overflowing max
204          * is a listed technique for finding the current value
205          */
206         if(prevcount!=NULL) {
207                 *prevcount=sem_handle->val;
208         }
209         
210         /* No idea why max is signed, but thats the spec :-( */
211         if(sem_handle->val+count > (guint32)sem_handle->max) {
212 #ifdef DEBUG
213                 g_message("%s: sem %p max value would be exceeded: max %d current %d count %d", __func__, handle, sem_handle->max, sem_handle->val, count);
214 #endif
215
216                 goto end;
217         }
218         
219         sem_handle->val+=count;
220         _wapi_handle_set_signal_state (handle, TRUE, TRUE);
221         
222         ret=TRUE;
223
224 #ifdef DEBUG
225         g_message("%s: sem %p val now %d", __func__, handle, sem_handle->val);
226 #endif
227         
228 end:
229         thr_ret = _wapi_handle_unlock_handle (handle);
230         g_assert (thr_ret == 0);
231         pthread_cleanup_pop (0);
232
233         return(ret);
234 }