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