2004-06-08 Martin Baulig <martin@ximian.com>
[mono.git] / mono / io-layer / handles-private.h
1 /*
2  * handles-private.h:  Internal operations on handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #ifndef _WAPI_HANDLES_PRIVATE_H_
11 #define _WAPI_HANDLES_PRIVATE_H_
12
13 #include <config.h>
14 #include <glib.h>
15
16 #include <mono/io-layer/wapi-private.h>
17 #include <mono/io-layer/shared.h>
18 #include <mono/io-layer/misc-private.h>
19
20 #undef DEBUG
21
22 /* Shared threads dont seem to work yet */
23 #undef _POSIX_THREAD_PROCESS_SHARED
24
25 extern struct _WapiHandleShared_list **_wapi_shared_data;
26 extern struct _WapiHandleScratch *_wapi_shared_scratch;
27 extern struct _WapiHandlePrivate_list **_wapi_private_data;
28 extern pthread_mutex_t _wapi_shared_mutex;
29 extern guint32 _wapi_shm_mapped_segments;
30
31 extern guint32 _wapi_handle_new_internal (WapiHandleType type);
32 extern gpointer _wapi_handle_new (WapiHandleType type);
33 extern gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
34                                      gpointer *shared, gpointer *private);
35 extern gpointer _wapi_search_handle (WapiHandleType type,
36                                      gboolean (*check)(gpointer, gpointer),
37                                      gpointer user_data,
38                                      gpointer *shared, gpointer *private);
39 extern gpointer _wapi_search_handle_namespace (WapiHandleType type,
40                                                gchar *utf8_name,
41                                                gpointer *shared,
42                                                gpointer *private);
43 extern void _wapi_handle_ref (gpointer handle);
44 extern void _wapi_handle_unref (gpointer handle);
45 extern guint32 _wapi_handle_scratch_store_internal (guint32 bytes,
46                                                     gboolean *remap);
47 extern guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes);
48 extern guint32 _wapi_handle_scratch_store_string_array (gchar **data);
49 extern gpointer _wapi_handle_scratch_lookup (guint32 idx);
50 extern gchar **_wapi_handle_scratch_lookup_string_array (guint32 idx);
51 extern void _wapi_handle_scratch_delete_internal (guint32 idx);
52 extern void _wapi_handle_scratch_delete (guint32 idx);
53 extern void _wapi_handle_scratch_delete_string_array (guint32 idx);
54 extern void _wapi_handle_register_capabilities (WapiHandleType type,
55                                                 WapiHandleCapability caps);
56 extern gboolean _wapi_handle_test_capabilities (gpointer handle,
57                                                 WapiHandleCapability caps);
58 extern void _wapi_handle_ops_close_shared (gpointer handle);
59 extern void _wapi_handle_ops_close_private (gpointer handle);
60 extern void _wapi_handle_ops_signal (gpointer handle);
61 extern void _wapi_handle_ops_own (gpointer handle);
62 extern gboolean _wapi_handle_ops_isowned (gpointer handle);
63
64 extern gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
65                                                       gpointer *handles,
66                                                       gboolean waitall,
67                                                       guint32 *retcount,
68                                                       guint32 *lowest);
69 extern void _wapi_handle_unlock_handles (guint32 numhandles,
70                                          gpointer *handles);
71 extern int _wapi_handle_wait_signal (void);
72 extern int _wapi_handle_timedwait_signal (struct timespec *timeout);
73 extern int _wapi_handle_wait_signal_handle (gpointer handle);
74 extern int _wapi_handle_timedwait_signal_handle (gpointer handle,
75                                                  struct timespec *timeout);
76 extern gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env,
77                                            guint32 dir, gboolean inherit,
78                                            guint32 flags,
79                                            gpointer stdin_handle,
80                                            gpointer stdout_handle,
81                                            gpointer stderr_handle,
82                                            gpointer *process_handle,
83                                            gpointer *thread_handle,
84                                            guint32 *pid, guint32 *tid);
85
86 extern gboolean _wapi_handle_process_kill (pid_t pid, guint32 signo,
87                                            gint *err);
88 extern gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
89                                                guint32 new_sharemode,
90                                                guint32 new_access,
91                                                guint32 *old_sharemode,
92                                                guint32 *old_access);
93 extern void _wapi_handle_set_share (dev_t device, ino_t inode,
94                                     guint32 sharemode, guint32 access);
95
96 static inline struct _WapiHandleShared_list *_wapi_handle_get_shared_segment (guint32 segment)
97 {
98         struct _WapiHandleShared_list *shared;
99         int thr_ret;
100         
101         pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
102                               (void *)&_wapi_shared_mutex);
103         thr_ret = pthread_mutex_lock (&_wapi_shared_mutex);
104         g_assert (thr_ret == 0);
105         
106         shared=_wapi_shared_data[segment];
107
108         thr_ret = pthread_mutex_unlock (&_wapi_shared_mutex);
109         g_assert (thr_ret == 0);
110         pthread_cleanup_pop (0);
111
112         return(shared);
113 }
114
115 static inline struct _WapiHandlePrivate_list *_wapi_handle_get_private_segment (guint32 segment)
116 {
117         struct _WapiHandlePrivate_list *priv;
118         int thr_ret;
119         
120         pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
121                               (void *)&_wapi_shared_mutex);
122         thr_ret = pthread_mutex_lock (&_wapi_shared_mutex);
123         g_assert (thr_ret == 0);
124         
125         priv=_wapi_private_data[segment];
126         
127         thr_ret = pthread_mutex_unlock (&_wapi_shared_mutex);
128         g_assert (thr_ret == 0);
129         pthread_cleanup_pop (0);
130         
131         return(priv);
132 }
133
134 static inline void _wapi_handle_ensure_mapped (guint32 segment)
135 {
136         int thr_ret;
137         
138 #ifdef DEBUG
139         g_message (G_GNUC_PRETTY_FUNCTION ": checking segment %d is mapped",
140                    segment);
141         g_message (G_GNUC_PRETTY_FUNCTION ": _wapi_shm_mapped_segments: %d",
142                    _wapi_shm_mapped_segments);
143         if(segment<_wapi_shm_mapped_segments) {
144                 g_message (G_GNUC_PRETTY_FUNCTION ": _wapi_handle_get_shared_segment(segment): %p", _wapi_handle_get_shared_segment (segment));
145         }
146 #endif
147
148         if(segment<_wapi_shm_mapped_segments &&
149            _wapi_handle_get_shared_segment (segment)!=NULL) {
150                 /* Got it already */
151                 return;
152         }
153         
154         pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
155                               (void *)&_wapi_shared_mutex);
156         thr_ret = pthread_mutex_lock (&_wapi_shared_mutex);
157         g_assert (thr_ret == 0);
158         
159         if(segment>=_wapi_shm_mapped_segments) {
160                 /* Need to extend the arrays.  We can't use g_renew
161                  * here, because the unmapped segments must be NULL,
162                  * and g_renew doesn't initialise the memory it
163                  * returns
164                  */
165                 gulong old_len, new_len;
166                 
167                 old_len=_wapi_shm_mapped_segments;
168                 new_len=segment+1;
169                 
170 #ifdef DEBUG
171                 g_message (G_GNUC_PRETTY_FUNCTION
172                            ": extending shared array: mapped_segments is %d",
173                            _wapi_shm_mapped_segments);
174 #endif
175                 
176                 _wapi_shared_data=_wapi_g_renew0 (_wapi_shared_data, sizeof(struct _WapiHandleShared_list *) * old_len, sizeof(struct _WapiHandleShared_list *) * new_len);
177
178                 if(_wapi_private_data!=NULL) {
179                         /* the daemon doesn't deal with private data */
180                         _wapi_private_data=_wapi_g_renew0 (_wapi_private_data, sizeof(struct _WapiHandlePrivate_list *) * old_len, sizeof(struct _WapiHandlePrivate_list *) * new_len);
181                 }
182                 
183                 _wapi_shm_mapped_segments=segment+1;
184         }
185         
186         if(_wapi_shared_data[segment]==NULL) {
187                 /* Need to map it too */
188 #ifdef DEBUG
189                 g_message (G_GNUC_PRETTY_FUNCTION ": mapping segment %d",
190                            segment);
191 #endif
192
193                 _wapi_shared_data[segment]=_wapi_shm_file_map (WAPI_SHM_DATA,
194                                                                segment, NULL,
195                                                                NULL);
196                 if(_wapi_private_data!=NULL) {
197                         /* the daemon doesn't deal with private data */
198                         _wapi_private_data[segment]=g_new0 (struct _WapiHandlePrivate_list, 1);
199                 }
200         }
201
202         thr_ret = pthread_mutex_unlock (&_wapi_shared_mutex);
203         g_assert (thr_ret == 0);
204         pthread_cleanup_pop (0);
205 }
206
207 static inline void _wapi_handle_segment (gpointer handle, guint32 *segment,
208                                          guint32 *idx)
209 {
210         guint32 h=GPOINTER_TO_UINT (handle);
211         div_t divvy;
212
213         divvy=div (h, _WAPI_HANDLES_PER_SEGMENT);
214         *segment=divvy.quot;
215         *idx=divvy.rem;
216 }
217
218 static inline guint32 _wapi_handle_index (guint32 segment, guint32 idx)
219 {
220         return((segment*_WAPI_HANDLES_PER_SEGMENT)+idx);
221 }
222
223 static inline WapiHandleType _wapi_handle_type (gpointer handle)
224 {
225         guint32 idx;
226         guint32 segment;
227         
228         _wapi_handle_segment (handle, &segment, &idx);
229
230         if(segment>=_wapi_shm_mapped_segments)
231                 return WAPI_HANDLE_UNUSED;
232         
233         return(_wapi_handle_get_shared_segment (segment)->handles[idx].type);
234 }
235
236 static inline void _wapi_handle_set_signal_state (gpointer handle,
237                                                   gboolean state,
238                                                   gboolean broadcast)
239 {
240         guint32 idx;
241         guint32 segment;
242         struct _WapiHandleShared *shared_handle;
243         int thr_ret;
244         
245         _wapi_handle_segment (handle, &segment, &idx);
246         shared_handle=&_wapi_handle_get_shared_segment (segment)->handles[idx];
247         
248 #ifdef DEBUG
249         g_message (G_GNUC_PRETTY_FUNCTION ": setting state of %p to %s (broadcast %s)", handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE");
250 #endif
251
252         if(state==TRUE) {
253                 /* Tell everyone blocking on a single handle */
254
255                 /* This function _must_ be called with
256                  * handle->signal_mutex locked
257                  */
258                 shared_handle->signalled=state;
259                 
260                 if(broadcast==TRUE) {
261                         thr_ret = pthread_cond_broadcast (&shared_handle->signal_cond);
262                         g_assert (thr_ret == 0);
263                 } else {
264                         thr_ret = pthread_cond_signal (&shared_handle->signal_cond);
265                         g_assert (thr_ret == 0);
266                 }
267
268                 /* Tell everyone blocking on multiple handles that something
269                  * was signalled
270                  */
271 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
272                 {
273                         struct _WapiHandleShared_list *segment0=_wapi_handle_get_shared_segment (0);
274                         
275                         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&segment0->signal_mutex);
276                         thr_ret = mono_mutex_lock (&segment0->signal_mutex);
277                         g_assert (thr_ret == 0);
278                         
279                         thr_ret = pthread_cond_broadcast (&segment0->signal_cond);
280                         g_assert (thr_ret == 0);
281                         
282                         thr_ret = mono_mutex_unlock (&segment0->signal_mutex);
283                         g_assert (thr_ret == 0);
284                         pthread_cleanup_pop (0);
285                 }
286 #else
287                 {
288                         struct _WapiHandlePrivate_list *segment0=_wapi_handle_get_private_segment (0);
289                         
290 #ifdef DEBUG
291                         g_message (G_GNUC_PRETTY_FUNCTION ": lock global signal mutex");
292 #endif
293
294                         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&segment0->signal_mutex);
295                         thr_ret = mono_mutex_lock (&segment0->signal_mutex);
296                         g_assert (thr_ret == 0);
297                         
298                         thr_ret = pthread_cond_broadcast (&segment0->signal_cond);
299                         g_assert (thr_ret == 0);
300
301 #ifdef DEBUG
302                         g_message (G_GNUC_PRETTY_FUNCTION ": unlock global signal mutex");
303 #endif
304
305                         thr_ret = mono_mutex_unlock (&segment0->signal_mutex);
306                         g_assert (thr_ret == 0);
307                         pthread_cleanup_pop (0);
308                 }
309 #endif /* _POSIX_THREAD_PROCESS_SHARED */
310         } else {
311                 shared_handle->signalled=state;
312         }
313 }
314
315 static inline gboolean _wapi_handle_issignalled (gpointer handle)
316 {
317         guint32 idx;
318         guint32 segment;
319         
320         _wapi_handle_segment (handle, &segment, &idx);
321         
322         return(_wapi_handle_get_shared_segment (segment)->handles[idx].signalled);
323 }
324
325 static inline int _wapi_handle_lock_signal_mutex (void)
326 {
327 #ifdef DEBUG
328         g_message (G_GNUC_PRETTY_FUNCTION ": lock global signal mutex");
329 #endif
330 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
331         return(mono_mutex_lock (&_wapi_handle_get_shared_segment (0)->signal_mutex));
332 #else
333         return(mono_mutex_lock (&_wapi_handle_get_private_segment (0)->signal_mutex));
334 #endif /* _POSIX_THREAD_PROCESS_SHARED */
335 }
336
337 /* the parameter makes it easier to call from a pthread cleanup handler */
338 static inline int _wapi_handle_unlock_signal_mutex (void *unused)
339 {
340 #ifdef DEBUG
341         g_message (G_GNUC_PRETTY_FUNCTION ": unlock global signal mutex");
342 #endif
343 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
344         return(mono_mutex_unlock (&_wapi_handle_get_shared_segment (0)->signal_mutex));
345 #else
346         return(mono_mutex_unlock (&_wapi_handle_get_private_segment (0)->signal_mutex));
347 #endif /* _POSIX_THREAD_PROCESS_SHARED */
348 }
349
350 static inline int _wapi_handle_lock_handle (gpointer handle)
351 {
352         guint32 idx;
353         guint32 segment;
354         
355 #ifdef DEBUG
356         g_message (G_GNUC_PRETTY_FUNCTION ": locking handle %p", handle);
357 #endif
358
359         _wapi_handle_ref (handle);
360         
361         _wapi_handle_segment (handle, &segment, &idx);
362         
363         return(mono_mutex_lock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex));
364 }
365
366 static inline int _wapi_handle_unlock_handle (gpointer handle)
367 {
368         guint32 idx;
369         guint32 segment;
370         int ret;
371         
372 #ifdef DEBUG
373         g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p", handle);
374 #endif
375
376         _wapi_handle_segment (handle, &segment, &idx);
377         
378         ret = mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
379
380         _wapi_handle_unref (handle);
381         
382         return(ret);
383 }
384
385 #endif /* _WAPI_HANDLES_PRIVATE_H_ */