Put network includes in sockets.h
[mono.git] / mono / io-layer / mutexes.c
1 /*
2  * mutexes.c:  Mutex 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 #include <string.h>
14 #include <unistd.h>
15
16 #include <mono/io-layer/wapi.h>
17 #include <mono/io-layer/wapi-private.h>
18 #include <mono/io-layer/misc-private.h>
19 #include <mono/io-layer/handles-private.h>
20 #include <mono/io-layer/mono-mutex.h>
21 #include <mono/io-layer/mutex-private.h>
22
23 #undef DEBUG
24
25 static void mutex_close_shared (gpointer handle);
26 static void mutex_signal(gpointer handle);
27 static void mutex_own (gpointer handle);
28 static gboolean mutex_is_owned (gpointer handle);
29
30 struct _WapiHandleOps _wapi_mutex_ops = {
31         mutex_close_shared,     /* close_shared */
32         NULL,                   /* close_private */
33         mutex_signal,           /* signal */
34         mutex_own,              /* own */
35         mutex_is_owned,         /* is_owned */
36 };
37
38 static pthread_once_t mutex_ops_once=PTHREAD_ONCE_INIT;
39
40 static void mutex_ops_init (void)
41 {
42         _wapi_handle_register_capabilities (WAPI_HANDLE_MUTEX,
43                                             WAPI_HANDLE_CAP_WAIT |
44                                             WAPI_HANDLE_CAP_SIGNAL |
45                                             WAPI_HANDLE_CAP_OWN);
46 }
47
48 static void mutex_close_shared (gpointer handle)
49 {
50         struct _WapiHandle_mutex *mutex_handle;
51         gboolean ok;
52         
53         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
54                                 (gpointer *)&mutex_handle, NULL);
55         if(ok==FALSE) {
56                 g_warning (G_GNUC_PRETTY_FUNCTION
57                            ": error looking up mutex handle %p", handle);
58                 return;
59         }
60         
61 #ifdef DEBUG
62         g_message(G_GNUC_PRETTY_FUNCTION ": closing mutex handle %p", handle);
63 #endif
64
65         if(mutex_handle->name!=0) {
66                 _wapi_handle_scratch_delete (mutex_handle->name);
67                 mutex_handle->name=0;
68         }
69 }
70
71 static void mutex_signal(gpointer handle)
72 {
73         ReleaseMutex(handle);
74 }
75
76 static void mutex_own (gpointer handle)
77 {
78         struct _WapiHandle_mutex *mutex_handle;
79         gboolean ok;
80         
81         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
82                                 (gpointer *)&mutex_handle, NULL);
83         if(ok==FALSE) {
84                 g_warning (G_GNUC_PRETTY_FUNCTION
85                            ": error looking up mutex handle %p", handle);
86                 return;
87         }
88         
89 #ifdef DEBUG
90         g_message(G_GNUC_PRETTY_FUNCTION ": owning mutex handle %p", handle);
91 #endif
92
93         _wapi_handle_set_signal_state (handle, FALSE, FALSE);
94         
95         mutex_handle->pid=getpid ();
96         mutex_handle->tid=pthread_self ();
97         mutex_handle->recursion++;
98
99 #ifdef DEBUG
100         g_message (G_GNUC_PRETTY_FUNCTION
101                    ": mutex handle %p locked %d times by %d:%ld", handle,
102                    mutex_handle->recursion, mutex_handle->pid,
103                    mutex_handle->tid);
104 #endif
105 }
106
107 static gboolean mutex_is_owned (gpointer handle)
108 {
109         struct _WapiHandle_mutex *mutex_handle;
110         gboolean ok;
111         
112         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
113                                 (gpointer *)&mutex_handle, NULL);
114         if(ok==FALSE) {
115                 g_warning (G_GNUC_PRETTY_FUNCTION
116                            ": error looking up mutex handle %p", handle);
117                 return(FALSE);
118         }
119         
120 #ifdef DEBUG
121         g_message(G_GNUC_PRETTY_FUNCTION
122                   ": testing ownership mutex handle %p", handle);
123 #endif
124
125         if(mutex_handle->recursion>0 &&
126            mutex_handle->pid==getpid () &&
127            mutex_handle->tid==pthread_self ()) {
128 #ifdef DEBUG
129                 g_message (G_GNUC_PRETTY_FUNCTION
130                            ": mutex handle %p owned by %d:%ld", handle,
131                            getpid (), pthread_self ());
132 #endif
133
134                 return(TRUE);
135         } else {
136 #ifdef DEBUG
137                 g_message (G_GNUC_PRETTY_FUNCTION
138                            ": mutex handle %p not owned by %d:%ld", handle,
139                            getpid (), pthread_self ());
140 #endif
141
142                 return(FALSE);
143         }
144 }
145
146 /**
147  * CreateMutex:
148  * @security: Ignored for now.
149  * @owned: If %TRUE, the mutex is created with the calling thread
150  * already owning the mutex.
151  * @name:Pointer to a string specifying the name of this mutex, or
152  * %NULL.
153  *
154  * Creates a new mutex handle.  A mutex is signalled when no thread
155  * owns it.  A thread acquires ownership of the mutex by waiting for
156  * it with WaitForSingleObject() or WaitForMultipleObjects().  A
157  * thread relinquishes ownership with ReleaseMutex().
158  *
159  * A thread that owns a mutex can specify the same mutex in repeated
160  * wait function calls without blocking.  The thread must call
161  * ReleaseMutex() an equal number of times to release the mutex.
162  *
163  * Return value: A new handle, or %NULL on error.
164  */
165 gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
166                         const guchar *name)
167 {
168         struct _WapiHandle_mutex *mutex_handle;
169         gpointer handle;
170         gboolean ok;
171         
172         pthread_once (&mutex_ops_once, mutex_ops_init);
173         
174         handle=_wapi_handle_new (WAPI_HANDLE_MUTEX);
175         if(handle==_WAPI_HANDLE_INVALID) {
176                 g_warning (G_GNUC_PRETTY_FUNCTION
177                            ": error creating mutex handle");
178                 return(NULL);
179         }
180
181         _wapi_handle_lock_handle (handle);
182         
183         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
184                                 (gpointer *)&mutex_handle, NULL);
185         if(ok==FALSE) {
186                 g_warning (G_GNUC_PRETTY_FUNCTION
187                            ": error looking up mutex handle %p", handle);
188                 _wapi_handle_unlock_handle (handle);
189                 return(NULL);
190         }
191
192         if(name!=NULL) {
193                 mutex_handle->name=_wapi_handle_scratch_store (name,
194                                                                strlen (name));
195         }
196         
197         if(owned==TRUE) {
198                 mutex_own (handle);
199         } else {
200                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
201         }
202         
203 #ifdef DEBUG
204         g_message (G_GNUC_PRETTY_FUNCTION ": returning mutex handle %p",
205                    handle);
206 #endif
207
208         _wapi_handle_unlock_handle (handle);
209
210         return(handle);
211 }
212
213 /**
214  * ReleaseMutex:
215  * @handle: The mutex handle.
216  *
217  * Releases ownership if the mutex handle @handle.
218  *
219  * Return value: %TRUE on success, %FALSE otherwise.  This function
220  * fails if the calling thread does not own the mutex @handle.
221  */
222 gboolean ReleaseMutex(gpointer handle)
223 {
224         struct _WapiHandle_mutex *mutex_handle;
225         gboolean ok;
226         pthread_t tid=pthread_self();
227         pid_t pid=getpid ();
228         
229         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
230                                 (gpointer *)&mutex_handle, NULL);
231         if(ok==FALSE) {
232                 g_warning (G_GNUC_PRETTY_FUNCTION
233                            ": error looking up mutex handle %p", handle);
234                 return(FALSE);
235         }
236
237         _wapi_handle_lock_handle (handle);
238         
239 #ifdef DEBUG
240         g_message(G_GNUC_PRETTY_FUNCTION ": Releasing mutex handle %p",
241                   handle);
242 #endif
243
244         if(mutex_handle->tid!=tid || mutex_handle->pid!=pid) {
245 #ifdef DEBUG
246                 g_message(G_GNUC_PRETTY_FUNCTION ": We don't own mutex handle %p (owned by %d:%ld, me %d:%ld)", handle, mutex_handle->pid, mutex_handle->tid, pid, tid);
247 #endif
248
249                 _wapi_handle_unlock_handle (handle);
250                 return(FALSE);
251         }
252
253         /* OK, we own this mutex */
254         mutex_handle->recursion--;
255         
256         if(mutex_handle->recursion==0) {
257 #ifdef DEBUG
258                 g_message(G_GNUC_PRETTY_FUNCTION ": Unlocking mutex handle %p",
259                           handle);
260 #endif
261
262                 mutex_handle->pid=0;
263                 mutex_handle->tid=0;
264                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
265         }
266
267         _wapi_handle_unlock_handle (handle);
268         
269         return(TRUE);
270 }