2005-02-05 Zoltan Varga <vargaz@freemail.hu>
[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 struct _WapiHandleShared_list *_wapi_handle_get_shared_segment (guint32 segment)
100 {
101         struct _WapiHandleShared_list *shared;
102         int thr_ret;
103         
104         pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
105                               (void *)&_wapi_shared_mutex);
106         thr_ret = pthread_mutex_lock (&_wapi_shared_mutex);
107         g_assert (thr_ret == 0);
108         
109         shared=_wapi_shared_data[segment];
110
111         thr_ret = pthread_mutex_unlock (&_wapi_shared_mutex);
112         g_assert (thr_ret == 0);
113         pthread_cleanup_pop (0);
114
115         return(shared);
116 }
117
118 static inline struct _WapiHandlePrivate_list *_wapi_handle_get_private_segment (guint32 segment)
119 {
120         struct _WapiHandlePrivate_list *priv;
121         int thr_ret;
122         
123         pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
124                               (void *)&_wapi_shared_mutex);
125         thr_ret = pthread_mutex_lock (&_wapi_shared_mutex);
126         g_assert (thr_ret == 0);
127         
128         priv=_wapi_private_data[segment];
129         
130         thr_ret = pthread_mutex_unlock (&_wapi_shared_mutex);
131         g_assert (thr_ret == 0);
132         pthread_cleanup_pop (0);
133         
134         return(priv);
135 }
136
137 static inline void _wapi_handle_ensure_mapped (guint32 segment)
138 {
139         int thr_ret;
140         
141 #ifdef DEBUG
142         g_message (G_GNUC_PRETTY_FUNCTION ": checking segment %d is mapped",
143                    segment);
144         g_message (G_GNUC_PRETTY_FUNCTION ": _wapi_shm_mapped_segments: %d",
145                    _wapi_shm_mapped_segments);
146         if(segment<_wapi_shm_mapped_segments) {
147                 g_message (G_GNUC_PRETTY_FUNCTION ": _wapi_handle_get_shared_segment(segment): %p", _wapi_handle_get_shared_segment (segment));
148         }
149 #endif
150
151         if(segment<_wapi_shm_mapped_segments &&
152            _wapi_handle_get_shared_segment (segment)!=NULL) {
153                 /* Got it already */
154                 return;
155         }
156         
157         pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
158                               (void *)&_wapi_shared_mutex);
159         thr_ret = pthread_mutex_lock (&_wapi_shared_mutex);
160         g_assert (thr_ret == 0);
161         
162         if(segment>=_wapi_shm_mapped_segments) {
163                 /* Need to extend the arrays.  We can't use g_renew
164                  * here, because the unmapped segments must be NULL,
165                  * and g_renew doesn't initialise the memory it
166                  * returns
167                  */
168                 gulong old_len, new_len;
169                 
170                 old_len=_wapi_shm_mapped_segments;
171                 new_len=segment+1;
172                 
173 #ifdef DEBUG
174                 g_message (G_GNUC_PRETTY_FUNCTION
175                            ": extending shared array: mapped_segments is %d",
176                            _wapi_shm_mapped_segments);
177 #endif
178                 
179                 _wapi_shared_data=_wapi_g_renew0 (_wapi_shared_data, sizeof(struct _WapiHandleShared_list *) * old_len, sizeof(struct _WapiHandleShared_list *) * new_len);
180
181                 if(_wapi_private_data!=NULL) {
182                         /* the daemon doesn't deal with private data */
183                         _wapi_private_data=_wapi_g_renew0 (_wapi_private_data, sizeof(struct _WapiHandlePrivate_list *) * old_len, sizeof(struct _WapiHandlePrivate_list *) * new_len);
184                 }
185                 
186                 _wapi_shm_mapped_segments=segment+1;
187         }
188         
189         if(_wapi_shared_data[segment]==NULL) {
190                 /* Need to map it too */
191 #ifdef DEBUG
192                 g_message (G_GNUC_PRETTY_FUNCTION ": mapping segment %d",
193                            segment);
194 #endif
195
196                 _wapi_shared_data[segment]=_wapi_shm_file_map (WAPI_SHM_DATA,
197                                                                segment, NULL,
198                                                                NULL);
199                 if(_wapi_private_data!=NULL) {
200                         /* the daemon doesn't deal with private data */
201                         _wapi_private_data[segment]=g_new0 (struct _WapiHandlePrivate_list, 1);
202                 }
203         }
204
205         thr_ret = pthread_mutex_unlock (&_wapi_shared_mutex);
206         g_assert (thr_ret == 0);
207         pthread_cleanup_pop (0);
208 }
209
210 static inline void _wapi_handle_segment (gpointer handle, guint32 *segment,
211                                          guint32 *idx)
212 {
213         guint32 h=GPOINTER_TO_UINT (handle);
214         div_t divvy;
215
216         divvy=div (h, _WAPI_HANDLES_PER_SEGMENT);
217         *segment=divvy.quot;
218         *idx=divvy.rem;
219 }
220
221 static inline guint32 _wapi_handle_index (guint32 segment, guint32 idx)
222 {
223         return((segment*_WAPI_HANDLES_PER_SEGMENT)+idx);
224 }
225
226 static inline gpointer _wapi_handle_fd_offset_to_handle (gpointer fd_handle)
227 {
228         int fd = GPOINTER_TO_INT (fd_handle);
229         gpointer handle;
230         
231         if (fd >= _wapi_fd_offset_table_size) {
232                 return(NULL);
233         }
234         
235         handle = _wapi_fd_offset_table[fd];
236         
237         if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
238                 return(NULL);
239         }
240
241 #ifdef DEBUG
242         g_message (G_GNUC_PRETTY_FUNCTION ": Returning fd offset %d of %p", fd,
243                    handle);
244 #endif
245
246         return(handle);
247 }
248
249 static inline WapiHandleType _wapi_handle_type (gpointer handle)
250 {
251         guint32 idx;
252         guint32 segment;
253         
254         if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
255                 handle = _wapi_handle_fd_offset_to_handle (handle);
256         }
257         
258         _wapi_handle_segment (handle, &segment, &idx);
259
260         if(segment>=_wapi_shm_mapped_segments)
261                 return WAPI_HANDLE_UNUSED;
262         
263         return(_wapi_handle_get_shared_segment (segment)->handles[idx].type);
264 }
265
266 static inline void _wapi_handle_fd_offset_store (int fd, gpointer handle)
267 {
268         g_assert (fd < _wapi_fd_offset_table_size);
269         
270         if (_wapi_fd_offset_table[fd] != NULL && handle != NULL) {
271                 gpointer oldhandle = _wapi_fd_offset_table[fd];
272                 struct _WapiHandlePrivate *private_handle;
273                 guint32 idx;
274                 guint32 segment;
275
276 #ifdef DEBUG
277                 g_message (G_GNUC_PRETTY_FUNCTION
278                            ": Reassigning fd offset %d from %p", fd,
279                            oldhandle);
280 #endif
281                 
282                 /* The WapiFDMapped struct at the head of the private
283                  * handle data means we don't need to do a full
284                  * lookup, and we don't need to know the handle type.
285                  */
286                 g_assert (_wapi_handle_type (oldhandle) == WAPI_HANDLE_FILE ||
287                           _wapi_handle_type (oldhandle) == WAPI_HANDLE_CONSOLE ||
288                           _wapi_handle_type (oldhandle) == WAPI_HANDLE_PIPE ||
289                           _wapi_handle_type (oldhandle) == WAPI_HANDLE_SOCKET);
290                 
291                 _wapi_handle_segment (oldhandle, &segment, &idx);
292                 _wapi_handle_ensure_mapped (segment);
293                 
294                 private_handle=&_wapi_handle_get_private_segment(segment)->handles[idx];
295                 ((WapiFDMapped *)(&private_handle->u))->assigned = FALSE;
296         }
297         
298         g_assert (GPOINTER_TO_UINT (handle) >= _wapi_fd_offset_table_size || handle==NULL);
299         
300 #ifdef DEBUG
301         g_message (G_GNUC_PRETTY_FUNCTION ": Assigning fd offset %d to %p", fd,
302                    handle);
303 #endif
304
305         _wapi_fd_offset_table[fd]=handle;
306 }
307
308 static inline void _wapi_handle_set_signal_state (gpointer handle,
309                                                   gboolean state,
310                                                   gboolean broadcast)
311 {
312         guint32 idx;
313         guint32 segment;
314         struct _WapiHandleShared *shared_handle;
315         int thr_ret;
316         
317         g_assert (GPOINTER_TO_UINT (handle) >= _wapi_fd_offset_table_size);
318         
319         _wapi_handle_segment (handle, &segment, &idx);
320         shared_handle=&_wapi_handle_get_shared_segment (segment)->handles[idx];
321         
322 #ifdef DEBUG
323         g_message (G_GNUC_PRETTY_FUNCTION ": setting state of %p to %s (broadcast %s)", handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE");
324 #endif
325
326         if(state==TRUE) {
327                 /* Tell everyone blocking on a single handle */
328
329                 /* This function _must_ be called with
330                  * handle->signal_mutex locked
331                  */
332                 shared_handle->signalled=state;
333                 
334                 if(broadcast==TRUE) {
335                         thr_ret = pthread_cond_broadcast (&shared_handle->signal_cond);
336                         g_assert (thr_ret == 0);
337                 } else {
338                         thr_ret = pthread_cond_signal (&shared_handle->signal_cond);
339                         g_assert (thr_ret == 0);
340                 }
341
342                 /* Tell everyone blocking on multiple handles that something
343                  * was signalled
344                  */
345 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
346                 {
347                         struct _WapiHandleShared_list *segment0=_wapi_handle_get_shared_segment (0);
348                         
349                         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&segment0->signal_mutex);
350                         thr_ret = mono_mutex_lock (&segment0->signal_mutex);
351                         g_assert (thr_ret == 0);
352                         
353                         thr_ret = pthread_cond_broadcast (&segment0->signal_cond);
354                         g_assert (thr_ret == 0);
355                         
356                         thr_ret = mono_mutex_unlock (&segment0->signal_mutex);
357                         g_assert (thr_ret == 0);
358                         pthread_cleanup_pop (0);
359                 }
360 #else
361                 {
362                         struct _WapiHandlePrivate_list *segment0=_wapi_handle_get_private_segment (0);
363                         
364 #ifdef DEBUG
365                         g_message (G_GNUC_PRETTY_FUNCTION ": lock global signal mutex");
366 #endif
367
368                         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&segment0->signal_mutex);
369                         thr_ret = mono_mutex_lock (&segment0->signal_mutex);
370                         g_assert (thr_ret == 0);
371                         
372                         thr_ret = pthread_cond_broadcast (&segment0->signal_cond);
373                         g_assert (thr_ret == 0);
374
375 #ifdef DEBUG
376                         g_message (G_GNUC_PRETTY_FUNCTION ": unlock global signal mutex");
377 #endif
378
379                         thr_ret = mono_mutex_unlock (&segment0->signal_mutex);
380                         g_assert (thr_ret == 0);
381                         pthread_cleanup_pop (0);
382                 }
383 #endif /* _POSIX_THREAD_PROCESS_SHARED */
384         } else {
385                 shared_handle->signalled=state;
386         }
387 }
388
389 static inline gboolean _wapi_handle_issignalled (gpointer handle)
390 {
391         guint32 idx;
392         guint32 segment;
393         
394         g_assert (GPOINTER_TO_UINT (handle) >= _wapi_fd_offset_table_size);
395         
396         _wapi_handle_segment (handle, &segment, &idx);
397         
398         return(_wapi_handle_get_shared_segment (segment)->handles[idx].signalled);
399 }
400
401 static inline int _wapi_handle_lock_signal_mutex (void)
402 {
403 #ifdef DEBUG
404         g_message (G_GNUC_PRETTY_FUNCTION ": lock global signal mutex");
405 #endif
406 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
407         return(mono_mutex_lock (&_wapi_handle_get_shared_segment (0)->signal_mutex));
408 #else
409         return(mono_mutex_lock (&_wapi_handle_get_private_segment (0)->signal_mutex));
410 #endif /* _POSIX_THREAD_PROCESS_SHARED */
411 }
412
413 /* the parameter makes it easier to call from a pthread cleanup handler */
414 static inline int _wapi_handle_unlock_signal_mutex (void *unused)
415 {
416 #ifdef DEBUG
417         g_message (G_GNUC_PRETTY_FUNCTION ": unlock global signal mutex");
418 #endif
419 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
420         return(mono_mutex_unlock (&_wapi_handle_get_shared_segment (0)->signal_mutex));
421 #else
422         return(mono_mutex_unlock (&_wapi_handle_get_private_segment (0)->signal_mutex));
423 #endif /* _POSIX_THREAD_PROCESS_SHARED */
424 }
425
426 static inline int _wapi_handle_lock_handle (gpointer handle)
427 {
428         guint32 idx;
429         guint32 segment;
430         
431         g_assert (GPOINTER_TO_UINT (handle) >= _wapi_fd_offset_table_size);
432         
433 #ifdef DEBUG
434         g_message (G_GNUC_PRETTY_FUNCTION ": locking handle %p", handle);
435 #endif
436
437         _wapi_handle_ref (handle);
438         
439         _wapi_handle_segment (handle, &segment, &idx);
440         
441         return(mono_mutex_lock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex));
442 }
443
444 static inline int _wapi_handle_unlock_handle (gpointer handle)
445 {
446         guint32 idx;
447         guint32 segment;
448         int ret;
449         
450         g_assert (GPOINTER_TO_UINT (handle) >= _wapi_fd_offset_table_size);
451         
452 #ifdef DEBUG
453         g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p", handle);
454 #endif
455
456         _wapi_handle_segment (handle, &segment, &idx);
457         
458         ret = mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
459
460         _wapi_handle_unref (handle);
461         
462         return(ret);
463 }
464
465 #endif /* _WAPI_HANDLES_PRIVATE_H_ */