f92b6566d8c4886f5e88bd1f40facfc4e44c8bf9
[mono.git] / mono / io-layer / handles.c
1 /*
2  * handles.c:  Generic and internal operations on handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002-2011 Novell, Inc.
8  * Copyright 2011 Xamarin Inc
9  */
10
11 #include <config.h>
12 #include <glib.h>
13 #include <pthread.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #ifdef HAVE_SIGNAL_H
17 #include <signal.h>
18 #endif
19 #include <string.h>
20 #include <sys/types.h>
21 #ifdef HAVE_SYS_SOCKET_H
22 #  include <sys/socket.h>
23 #endif
24 #ifdef HAVE_SYS_UN_H
25 #  include <sys/un.h>
26 #endif
27 #ifdef HAVE_SYS_MMAN_H
28 #  include <sys/mman.h>
29 #endif
30 #ifdef HAVE_DIRENT_H
31 #  include <dirent.h>
32 #endif
33 #include <sys/stat.h>
34 #ifdef HAVE_SYS_RESOURCE_H
35 #  include <sys/resource.h>
36 #endif
37
38 #include <mono/io-layer/wapi.h>
39 #include <mono/io-layer/wapi-private.h>
40 #include <mono/io-layer/handles-private.h>
41 #include <mono/io-layer/shared.h>
42 #include <mono/io-layer/process-private.h>
43
44 #include <mono/utils/mono-os-mutex.h>
45 #include <mono/utils/mono-proclib.h>
46 #include <mono/utils/mono-threads.h>
47 #include <mono/utils/mono-once.h>
48 #undef DEBUG_REFS
49
50 #if 0
51 #define DEBUG(...) g_message(__VA_ARGS__)
52 #else
53 #define DEBUG(...)
54 #endif
55
56 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
57
58 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT] = { (WapiHandleCapability)0 };
59 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
60         NULL,
61         &_wapi_file_ops,
62         &_wapi_console_ops,
63         &_wapi_thread_ops,
64         &_wapi_sem_ops,
65         &_wapi_mutex_ops,
66         &_wapi_event_ops,
67 #ifndef DISABLE_SOCKETS
68         &_wapi_socket_ops,
69 #endif
70         &_wapi_find_ops,
71         &_wapi_process_ops,
72         &_wapi_pipe_ops,
73         &_wapi_namedmutex_ops,
74         &_wapi_namedsem_ops,
75         &_wapi_namedevent_ops,
76 };
77
78 static void _wapi_shared_details (gpointer handle_info);
79
80 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
81         NULL,
82         _wapi_file_details,
83         _wapi_console_details,
84         _wapi_shared_details,   /* thread */
85         _wapi_sem_details,
86         _wapi_mutex_details,
87         _wapi_event_details,
88         NULL,                   /* Nothing useful to see in a socket handle */
89         NULL,                   /* Nothing useful to see in a find handle */
90         _wapi_shared_details,   /* process */
91         _wapi_pipe_details,
92         _wapi_shared_details,   /* namedmutex */
93         _wapi_shared_details,   /* namedsem */
94         _wapi_shared_details,   /* namedevent */
95 };
96
97 const char *_wapi_handle_typename[] = {
98         "Unused",
99         "File",
100         "Console",
101         "Thread",
102         "Sem",
103         "Mutex",
104         "Event",
105         "Socket",
106         "Find",
107         "Process",
108         "Pipe",
109         "N.Mutex",
110         "N.Sem",
111         "N.Event",
112         "Error!!"
113 };
114
115 /*
116  * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
117  * If 4M handles are not enough... Oh, well... we will crash.
118  */
119 #define SLOT_INDEX(x)   (x / _WAPI_HANDLE_INITIAL_COUNT)
120 #define SLOT_OFFSET(x)  (x % _WAPI_HANDLE_INITIAL_COUNT)
121
122 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
123 static guint32 _wapi_private_handle_count = 0;
124 static guint32 _wapi_private_handle_slot_count = 0;
125
126 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
127
128 /*
129  * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
130  * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
131  * 4MB array.
132  */
133 static GHashTable *file_share_hash;
134 static mono_mutex_t file_share_hash_mutex;
135
136 #define file_share_hash_lock() mono_os_mutex_lock (&file_share_hash_mutex)
137 #define file_share_hash_unlock() mono_os_mutex_unlock (&file_share_hash_mutex)
138
139 guint32 _wapi_fd_reserve;
140
141 /* 
142  * This is an internal handle which is used for handling waiting for multiple handles.
143  * Threads which wait for multiple handles wait on this one handle, and when a handle
144  * is signalled, this handle is signalled too.
145  */
146 static gpointer _wapi_global_signal_handle;
147
148 /* Point to the mutex/cond inside _wapi_global_signal_handle */
149 mono_mutex_t *_wapi_global_signal_mutex;
150 pthread_cond_t *_wapi_global_signal_cond;
151
152 int _wapi_sem_id;
153 gboolean _wapi_has_shut_down = FALSE;
154
155 /* Use this instead of getpid(), to cope with linuxthreads.  It's a
156  * function rather than a variable lookup because we need to get at
157  * this before share_init() might have been called.
158  */
159 static pid_t _wapi_pid;
160 static mono_once_t pid_init_once = MONO_ONCE_INIT;
161
162 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
163
164 static void pid_init (void)
165 {
166         _wapi_pid = getpid ();
167 }
168
169 pid_t _wapi_getpid (void)
170 {
171         mono_once (&pid_init_once, pid_init);
172         
173         return(_wapi_pid);
174 }
175
176
177 static mono_mutex_t scan_mutex;
178
179 static void handle_cleanup (void)
180 {
181         int i, j, k;
182         
183         /* Every shared handle we were using ought really to be closed
184          * by now, but to make sure just blow them all away.  The
185          * exiting finalizer thread in particular races us to the
186          * program exit and doesn't always win, so it can be left
187          * cluttering up the shared file.  Anything else left over is
188          * really a bug.
189          */
190         for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
191                 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
192                         struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
193                         gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
194
195                         for(k = handle_data->ref; k > 0; k--) {
196                                 DEBUG ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
197                                         
198                                 _wapi_handle_unref_full (handle, TRUE);
199                         }
200                 }
201         }
202         
203         _wapi_shm_semaphores_remove ();
204
205         g_free (_wapi_shared_layout);
206
207         if (file_share_hash) {
208                 g_hash_table_destroy (file_share_hash);
209                 mono_os_mutex_destroy (&file_share_hash_mutex);
210         }
211
212         for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
213                 g_free (_wapi_private_handles [i]);
214 }
215
216 int
217 wapi_getdtablesize (void)
218 {
219         return eg_getdtablesize ();
220 }
221
222 /*
223  * wapi_init:
224  *
225  *   Initialize the io-layer.
226  */
227 void
228 wapi_init (void)
229 {
230         g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
231                   == WAPI_HANDLE_COUNT);
232
233         _wapi_fd_reserve = wapi_getdtablesize ();
234
235         /* This is needed by the code in _wapi_handle_new_internal */
236         _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
237
238         do {
239                 /* 
240                  * The entries in _wapi_private_handles reserved for fds are allocated lazily to 
241                  * save memory.
242                  */
243                 /*
244                 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
245                                                         _WAPI_HANDLE_INITIAL_COUNT);
246                 */
247
248                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
249                 _wapi_private_handle_slot_count ++;
250         } while(_wapi_fd_reserve > _wapi_private_handle_count);
251
252         _wapi_shm_semaphores_init ();
253
254         _wapi_shared_layout = (_WapiHandleSharedLayout *)g_malloc0 (sizeof (_WapiHandleSharedLayout));
255         g_assert (_wapi_shared_layout != NULL);
256
257         _wapi_io_init ();
258         mono_os_mutex_init (&scan_mutex);
259
260         _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
261
262         _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
263         _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
264
265         wapi_processes_init ();
266 }
267
268 void
269 wapi_cleanup (void)
270 {
271         g_assert (_wapi_has_shut_down == FALSE);
272         
273         _wapi_has_shut_down = TRUE;
274
275         _wapi_error_cleanup ();
276         _wapi_thread_cleanup ();
277         wapi_processes_cleanup ();
278         handle_cleanup ();
279 }
280
281 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
282                                       WapiHandleType type,
283                                       gpointer handle_specific)
284 {
285         g_assert (_wapi_has_shut_down == FALSE);
286         
287         handle->type = type;
288         handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
289         handle->signalled = FALSE;
290         handle->handle_refs = 1;
291         
292         if (handle_specific != NULL) {
293                 memcpy (&handle->u, handle_specific, sizeof (handle->u));
294         }
295 }
296
297 static size_t _wapi_handle_struct_size (WapiHandleType type)
298 {
299         size_t type_size;
300
301         switch (type) {
302                 case WAPI_HANDLE_FILE: case WAPI_HANDLE_CONSOLE: case WAPI_HANDLE_PIPE:
303                         type_size = sizeof (struct _WapiHandle_file);
304                         break;
305                 case WAPI_HANDLE_THREAD:
306                         type_size = sizeof (struct _WapiHandle_thread);
307                         break;
308                 case WAPI_HANDLE_SEM:
309                         type_size = sizeof (struct _WapiHandle_sem);
310                         break;
311                 case WAPI_HANDLE_MUTEX:
312                         type_size = sizeof (struct _WapiHandle_mutex);
313                         break;
314                 case WAPI_HANDLE_EVENT:
315                         type_size = sizeof (struct _WapiHandle_event);
316                         break;
317                 case WAPI_HANDLE_SOCKET:
318                         type_size = sizeof (struct _WapiHandle_socket);
319                         break;
320                 case WAPI_HANDLE_FIND:
321                         type_size = sizeof (struct _WapiHandle_find);
322                         break;
323                 case WAPI_HANDLE_PROCESS:
324                         type_size = sizeof (struct _WapiHandle_process);
325                         break;
326                 case WAPI_HANDLE_NAMEDMUTEX:
327                         type_size = sizeof (struct _WapiHandle_namedmutex);
328                         break;
329                 case WAPI_HANDLE_NAMEDSEM:
330                         type_size = sizeof (struct _WapiHandle_namedsem);
331                         break;
332                 case WAPI_HANDLE_NAMEDEVENT:
333                         type_size = sizeof (struct _WapiHandle_namedevent);
334                         break;
335
336                 default:
337                         g_error ("Unknown WapiHandleType: %d\n", type);
338         }
339
340         return type_size;
341 }
342
343 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
344                                WapiHandleType type, gpointer handle_specific)
345 {
346         int thr_ret;
347         int type_size;
348         
349         g_assert (_wapi_has_shut_down == FALSE);
350         
351         handle->type = type;
352         handle->signalled = FALSE;
353         handle->ref = 1;
354         
355         if (!_WAPI_SHARED_HANDLE(type)) {
356                 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
357                 g_assert (thr_ret == 0);
358                                 
359                 thr_ret = mono_os_mutex_init (&handle->signal_mutex);
360                 g_assert (thr_ret == 0);
361
362                 if (handle_specific != NULL) {
363                         type_size = _wapi_handle_struct_size (type);
364                         memcpy (&handle->u, handle_specific,
365                                 type_size);
366                 }
367         }
368 }
369
370 static guint32 _wapi_handle_new_shared (WapiHandleType type,
371                                         gpointer handle_specific)
372 {
373         guint32 offset;
374         static guint32 last = 1;
375         int thr_ret;
376         
377         g_assert (_wapi_has_shut_down == FALSE);
378         
379         /* Leave the first slot empty as a guard */
380 again:
381         /* FIXME: expandable array */
382         for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
383                 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
384                 
385                 if(handle->type == WAPI_HANDLE_UNUSED) {
386                         thr_ret = _wapi_handle_lock_shared_handles ();
387                         g_assert (thr_ret == 0);
388                         
389                         if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
390                                 last = offset + 1;
391                         
392                                 _wapi_handle_init_shared (handle, type,
393                                                           handle_specific);
394
395                                 _wapi_handle_unlock_shared_handles ();
396                                 
397                                 return(offset);
398                         } else {
399                                 /* Someone else beat us to it, just
400                                  * continue looking
401                                  */
402                         }
403
404                         _wapi_handle_unlock_shared_handles ();
405                 }
406         }
407
408         if(last > 1) {
409                 /* Try again from the beginning */
410                 last = 1;
411                 goto again;
412         }
413
414         /* Will need to expand the array.  The caller will sort it out */
415
416         return(0);
417 }
418
419 /*
420  * _wapi_handle_new_internal:
421  * @type: Init handle to this type
422  *
423  * Search for a free handle and initialize it. Return the handle on
424  * success and 0 on failure.  This is only called from
425  * _wapi_handle_new, and scan_mutex must be held.
426  */
427 static guint32 _wapi_handle_new_internal (WapiHandleType type,
428                                           gpointer handle_specific)
429 {
430         guint32 i, k, count;
431         static guint32 last = 0;
432         gboolean retry = FALSE;
433         
434         g_assert (_wapi_has_shut_down == FALSE);
435         
436         /* A linear scan should be fast enough.  Start from the last
437          * allocation, assuming that handles are allocated more often
438          * than they're freed. Leave the space reserved for file
439          * descriptors
440          */
441         
442         if (last < _wapi_fd_reserve) {
443                 last = _wapi_fd_reserve;
444         } else {
445                 retry = TRUE;
446         }
447
448 again:
449         count = last;
450         for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
451                 if (_wapi_private_handles [i]) {
452                         for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
453                                 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
454
455                                 if(handle->type == WAPI_HANDLE_UNUSED) {
456                                         last = count + 1;
457                         
458                                         _wapi_handle_init (handle, type, handle_specific);
459                                         return (count);
460                                 }
461                                 count++;
462                         }
463                 }
464         }
465
466         if(retry && last > _wapi_fd_reserve) {
467                 /* Try again from the beginning */
468                 last = _wapi_fd_reserve;
469                 goto again;
470         }
471
472         /* Will need to expand the array.  The caller will sort it out */
473
474         return(0);
475 }
476
477 gpointer 
478 _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
479 {
480         guint32 handle_idx = 0;
481         gpointer handle;
482         int thr_ret;
483
484         g_assert (_wapi_has_shut_down == FALSE);
485                 
486         DEBUG ("%s: Creating new handle of type %s", __func__,
487                    _wapi_handle_typename[type]);
488
489         g_assert(!_WAPI_FD_HANDLE(type));
490         
491         thr_ret = mono_os_mutex_lock (&scan_mutex);
492         g_assert (thr_ret == 0);
493                 
494         while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
495                 /* Try and expand the array, and have another go */
496                 int idx = SLOT_INDEX (_wapi_private_handle_count);
497                 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
498                         break;
499                 }
500
501                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
502                                                 _WAPI_HANDLE_INITIAL_COUNT);
503
504                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
505                 _wapi_private_handle_slot_count ++;
506         }
507         
508         thr_ret = mono_os_mutex_unlock (&scan_mutex);
509         g_assert (thr_ret == 0);
510
511         if (handle_idx == 0) {
512                 /* We ran out of slots */
513                 handle = _WAPI_HANDLE_INVALID;
514                 goto done;
515         }
516                 
517         /* Make sure we left the space for fd mappings */
518         g_assert (handle_idx >= _wapi_fd_reserve);
519         
520         handle = GUINT_TO_POINTER (handle_idx);
521
522         DEBUG ("%s: Allocated new handle %p", __func__, handle);
523         
524         if (_WAPI_SHARED_HANDLE(type)) {
525                 /* Add the shared section too */
526                 guint32 ref;
527                 
528                 ref = _wapi_handle_new_shared (type, handle_specific);
529                 if (ref == 0) {
530                         ref = _wapi_handle_new_shared (type, handle_specific);
531                         if (ref == 0) {
532                                 /* FIXME: grow the arrays */
533                                 handle = _WAPI_HANDLE_INVALID;
534                                 goto done;
535                         }
536                 }
537                 
538                 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
539                 DEBUG ("%s: New shared handle at offset 0x%x", __func__,
540                            ref);
541         }
542                 
543 done:
544         return(handle);
545 }
546
547 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
548                                        gboolean timestamp)
549 {
550         guint32 handle_idx = 0;
551         gpointer handle = INVALID_HANDLE_VALUE;
552         int thr_ret, i, k;
553         struct _WapiHandleShared *shared;
554         
555         g_assert (_wapi_has_shut_down == FALSE);
556         
557         DEBUG ("%s: Creating new handle of type %s to offset %d", __func__,
558                    _wapi_handle_typename[type], offset);
559
560         g_assert(!_WAPI_FD_HANDLE(type));
561         g_assert(_WAPI_SHARED_HANDLE(type));
562         g_assert(offset != 0);
563
564         shared = &_wapi_shared_layout->handles[offset];
565         if (timestamp) {
566                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
567                 /* Bump up the timestamp for this offset */
568                 InterlockedExchange ((gint32 *)&shared->timestamp, now);
569         }
570                 
571         thr_ret = mono_os_mutex_lock (&scan_mutex);
572         g_assert (thr_ret == 0);
573
574         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
575                 if (_wapi_private_handles [i]) {
576                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
577                                 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
578                 
579                                 if (handle_data->type == type &&
580                                         handle_data->u.shared.offset == offset) {
581                                         handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
582                                         goto first_pass_done;
583                                 }
584                         }
585                 }
586         }
587
588 first_pass_done:
589         thr_ret = mono_os_mutex_unlock (&scan_mutex);
590         g_assert (thr_ret == 0);
591
592         if (handle != INVALID_HANDLE_VALUE) {
593                 _wapi_handle_ref (handle);
594
595                 DEBUG ("%s: Returning old handle %p referencing 0x%x",
596                            __func__, handle, offset);
597                 return (handle);
598         }
599
600         /* Prevent entries expiring under us as we search */
601         thr_ret = _wapi_handle_lock_shared_handles ();
602         g_assert (thr_ret == 0);
603         
604         if (shared->type == WAPI_HANDLE_UNUSED) {
605                 /* Someone deleted this handle while we were working */
606                 DEBUG ("%s: Handle at 0x%x unused", __func__, offset);
607                 goto done;
608         }
609
610         if (shared->type != type) {
611                 DEBUG ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
612                            __func__, offset, offset,
613                            _wapi_handle_typename[shared->type],
614                            _wapi_handle_typename[type]);
615                 goto done;
616         }
617         
618         thr_ret = mono_os_mutex_lock (&scan_mutex);
619         g_assert (thr_ret == 0);
620         
621         while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
622                 /* Try and expand the array, and have another go */
623                 int idx = SLOT_INDEX (_wapi_private_handle_count);
624                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
625                                                 _WAPI_HANDLE_INITIAL_COUNT);
626
627                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
628                 _wapi_private_handle_slot_count ++;
629         }
630                 
631         thr_ret = mono_os_mutex_unlock (&scan_mutex);
632         g_assert (thr_ret == 0);
633                 
634         /* Make sure we left the space for fd mappings */
635         g_assert (handle_idx >= _wapi_fd_reserve);
636         
637         handle = GUINT_TO_POINTER (handle_idx);
638                 
639         _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
640         InterlockedIncrement ((gint32 *)&shared->handle_refs);
641         
642         DEBUG ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
643         
644 done:
645         _wapi_handle_unlock_shared_handles ();
646
647         return(handle);
648 }
649
650 static void
651 init_handles_slot (int idx)
652 {
653         int thr_ret;
654
655         thr_ret = mono_os_mutex_lock (&scan_mutex);
656         g_assert (thr_ret == 0);
657
658         if (_wapi_private_handles [idx] == NULL) {
659                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
660                                                                                           _WAPI_HANDLE_INITIAL_COUNT);
661                 g_assert (_wapi_private_handles [idx]);
662         }
663
664         thr_ret = mono_os_mutex_unlock (&scan_mutex);
665         g_assert (thr_ret == 0);
666 }
667
668 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
669                               gpointer handle_specific)
670 {
671         struct _WapiHandleUnshared *handle;
672         int thr_ret;
673         
674         g_assert (_wapi_has_shut_down == FALSE);
675         
676         DEBUG ("%s: Creating new handle of type %s", __func__,
677                    _wapi_handle_typename[type]);
678         
679         g_assert(_WAPI_FD_HANDLE(type));
680         g_assert(!_WAPI_SHARED_HANDLE(type));
681         
682         if (fd >= _wapi_fd_reserve) {
683                 DEBUG ("%s: fd %d is too big", __func__, fd);
684
685                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
686         }
687
688         /* Initialize the array entries on demand */
689         if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
690                 init_handles_slot (SLOT_INDEX (fd));
691
692         handle = &_WAPI_PRIVATE_HANDLES(fd);
693         
694         if (handle->type != WAPI_HANDLE_UNUSED) {
695                 DEBUG ("%s: fd %d is already in use!", __func__, fd);
696                 /* FIXME: clean up this handle?  We can't do anything
697                  * with the fd, cos thats the new one
698                  */
699         }
700
701         DEBUG ("%s: Assigning new fd handle %d", __func__, fd);
702
703         /* Prevent file share entries racing with us, when the file
704          * handle is only half initialised
705          */
706         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
707         g_assert(thr_ret == 0);
708
709         _wapi_handle_init (handle, type, handle_specific);
710
711         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
712
713         return(GUINT_TO_POINTER(fd));
714 }
715
716 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
717                               gpointer *handle_specific)
718 {
719         struct _WapiHandleUnshared *handle_data;
720         guint32 handle_idx = GPOINTER_TO_UINT(handle);
721
722         if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
723                 return(FALSE);
724         }
725
726         /* Initialize the array entries on demand */
727         if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
728                 init_handles_slot (SLOT_INDEX (handle_idx));
729         
730         handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
731         
732         if (handle_data->type != type) {
733                 return(FALSE);
734         }
735
736         if (handle_specific == NULL) {
737                 return(FALSE);
738         }
739         
740         if (_WAPI_SHARED_HANDLE(type)) {
741                 struct _WapiHandle_shared_ref *ref;
742                 struct _WapiHandleShared *shared_handle_data;
743                         
744                 ref = &handle_data->u.shared;
745                 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
746                 
747                 if (shared_handle_data->type != type) {
748                         /* The handle must have been deleted on us
749                          */
750                         return (FALSE);
751                 }
752                 
753                 *handle_specific = &shared_handle_data->u;
754         } else {
755                 *handle_specific = &handle_data->u;
756         }
757         
758         return(TRUE);
759 }
760
761 void
762 _wapi_handle_foreach (WapiHandleType type,
763                         gboolean (*on_each)(gpointer test, gpointer user),
764                         gpointer user_data)
765 {
766         struct _WapiHandleUnshared *handle_data = NULL;
767         gpointer ret = NULL;
768         guint32 i, k;
769         int thr_ret;
770
771         thr_ret = mono_os_mutex_lock (&scan_mutex);
772         g_assert (thr_ret == 0);
773
774         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
775                 if (_wapi_private_handles [i]) {
776                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
777                                 handle_data = &_wapi_private_handles [i][k];
778                         
779                                 if (handle_data->type == type) {
780                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
781                                         if (on_each (ret, user_data) == TRUE)
782                                                 break;
783                                 }
784                         }
785                 }
786         }
787
788         thr_ret = mono_os_mutex_unlock (&scan_mutex);
789         g_assert (thr_ret == 0);
790 }
791
792 /* This might list some shared handles twice if they are already
793  * opened by this process, and the check function returns FALSE the
794  * first time.  Shared handles that are created during the search are
795  * unreffed if the check function returns FALSE, so callers must not
796  * rely on the handle persisting (unless the check function returns
797  * TRUE)
798  * The caller owns the returned handle.
799  */
800 gpointer _wapi_search_handle (WapiHandleType type,
801                               gboolean (*check)(gpointer test, gpointer user),
802                               gpointer user_data,
803                               gpointer *handle_specific,
804                               gboolean search_shared)
805 {
806         struct _WapiHandleUnshared *handle_data = NULL;
807         struct _WapiHandleShared *shared = NULL;
808         gpointer ret = NULL;
809         guint32 i, k;
810         gboolean found = FALSE;
811         int thr_ret;
812
813         thr_ret = mono_os_mutex_lock (&scan_mutex);
814         g_assert (thr_ret == 0);
815         
816         for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
817                 if (_wapi_private_handles [i]) {
818                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
819                                 handle_data = &_wapi_private_handles [i][k];
820                 
821                                 if (handle_data->type == type) {
822                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
823                                         if (check (ret, user_data) == TRUE) {
824                                                 _wapi_handle_ref (ret);
825                                                 found = TRUE;
826
827                                                 if (_WAPI_SHARED_HANDLE (type)) {
828                                                         shared = &_wapi_shared_layout->handles[i];
829                                                 }
830                                         
831                                                 break;
832                                         }
833                                 }
834                         }
835                 }
836         }
837
838         thr_ret = mono_os_mutex_unlock (&scan_mutex);
839         g_assert (thr_ret == 0);
840
841         if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
842                 /* Not found yet, so search the shared memory too */
843                 DEBUG ("%s: Looking at other shared handles...", __func__);
844
845                 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
846                         shared = &_wapi_shared_layout->handles[i];
847                         
848                         if (shared->type == type) {
849                                 /* Tell new_from_offset to not
850                                  * timestamp this handle, because
851                                  * otherwise it will ping every handle
852                                  * in the list and they will never
853                                  * expire
854                                  */
855                                 ret = _wapi_handle_new_from_offset (type, i,
856                                                                     FALSE);
857                                 if (ret == INVALID_HANDLE_VALUE) {
858                                         /* This handle was deleted
859                                          * while we were looking at it
860                                          */
861                                         continue;
862                                 }
863                                 
864                                 DEBUG ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
865
866                                 /* It's possible that the shared part
867                                  * of this handle has now been blown
868                                  * away (after new_from_offset
869                                  * successfully opened it,) if its
870                                  * timestamp is too old.  The check
871                                  * function needs to be aware of this,
872                                  * and cope if the handle has
873                                  * vanished.
874                                  */
875                                 if (check (ret, user_data) == TRUE) {
876                                         /* Timestamp this handle, but make
877                                          * sure it still exists first
878                                          */
879                                         thr_ret = _wapi_handle_lock_shared_handles ();
880                                         g_assert (thr_ret == 0);
881                                         
882                                         if (shared->type == type) {
883                                                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
884                                                 InterlockedExchange ((gint32 *)&shared->timestamp, now);
885
886                                                 found = TRUE;
887                                                 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
888                                         
889                                                 _wapi_handle_unlock_shared_handles ();
890                                                 break;
891                                         } else {
892                                                 /* It's been deleted,
893                                                  * so just keep
894                                                  * looking
895                                                  */
896                                                 _wapi_handle_unlock_shared_handles ();
897                                         }
898                                 }
899                                 
900                                 /* This isn't the handle we're looking
901                                  * for, so drop the reference we took
902                                  * in _wapi_handle_new_from_offset ()
903                                  */
904                                 _wapi_handle_unref (ret);
905                         }
906                 }
907         }
908         
909         if (!found) {
910                 ret = NULL;
911                 goto done;
912         }
913         
914         if(handle_specific != NULL) {
915                 if (_WAPI_SHARED_HANDLE(type)) {
916                         g_assert(shared->type == type);
917                         
918                         *handle_specific = &shared->u;
919                 } else {
920                         *handle_specific = &handle_data->u;
921                 }
922         }
923
924 done:
925         return(ret);
926 }
927
928 /* Returns the offset of the metadata array, or -1 on error, or 0 for
929  * not found (0 is not a valid offset)
930  */
931 gint32 _wapi_search_handle_namespace (WapiHandleType type,
932                                       gchar *utf8_name)
933 {
934         struct _WapiHandleShared *shared_handle_data;
935         guint32 i;
936         gint32 ret = 0;
937         int thr_ret;
938         
939         g_assert(_WAPI_SHARED_HANDLE(type));
940         
941         DEBUG ("%s: Lookup for handle named [%s] type %s", __func__,
942                    utf8_name, _wapi_handle_typename[type]);
943
944         thr_ret = _wapi_handle_lock_shared_handles ();
945         g_assert (thr_ret == 0);
946         
947         for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
948                 WapiSharedNamespace *sharedns;
949                 
950                 shared_handle_data = &_wapi_shared_layout->handles[i];
951
952                 /* Check mutex, event, semaphore, timer, job and
953                  * file-mapping object names.  So far only mutex,
954                  * semaphore and event are implemented.
955                  */
956                 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
957                         continue;
958                 }
959
960                 DEBUG ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
961
962                 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
963                         
964                 DEBUG ("%s: name is [%s]", __func__, sharedns->name);
965
966                 if (strcmp (sharedns->name, utf8_name) == 0) {
967                         if (shared_handle_data->type != type) {
968                                 /* Its the wrong type, so fail now */
969                                 DEBUG ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
970                                 ret = -1;
971                                 goto done;
972                         } else {
973                                 DEBUG ("%s: handle 0x%x matches name and type", __func__, i);
974                                 ret = i;
975                                 goto done;
976                         }
977                 }
978         }
979
980 done:
981         _wapi_handle_unlock_shared_handles ();
982         
983         return(ret);
984 }
985
986 void _wapi_handle_ref (gpointer handle)
987 {
988         guint32 idx = GPOINTER_TO_UINT(handle);
989         struct _WapiHandleUnshared *handle_data;
990
991         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
992                 return;
993         }
994         
995         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
996                 g_warning ("%s: Attempting to ref unused handle %p", __func__,
997                            handle);
998                 return;
999         }
1000
1001         handle_data = &_WAPI_PRIVATE_HANDLES(idx);
1002         
1003         InterlockedIncrement ((gint32 *)&handle_data->ref);
1004
1005         /* It's possible for processes to exit before getting around
1006          * to updating timestamps in the collection thread, so if a
1007          * shared handle is reffed do the timestamp here as well just
1008          * to make sure.
1009          */
1010         if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1011                 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1012                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1013                 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1014         }
1015         
1016 #ifdef DEBUG_REFS
1017         g_message ("%s: %s handle %p ref now %d", __func__, 
1018                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1019                    handle,
1020                    _WAPI_PRIVATE_HANDLES(idx).ref);
1021 #endif
1022 }
1023
1024 /* The handle must not be locked on entry to this function */
1025 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
1026 {
1027         guint32 idx = GPOINTER_TO_UINT(handle);
1028         gboolean destroy = FALSE, early_exit = FALSE;
1029         int thr_ret;
1030
1031         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1032                 return;
1033         }
1034         
1035         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1036                 g_warning ("%s: Attempting to unref unused handle %p",
1037                            __func__, handle);
1038                 return;
1039         }
1040
1041         /* Possible race condition here if another thread refs the
1042          * handle between here and setting the type to UNUSED.  I
1043          * could lock a mutex, but I'm not sure that allowing a handle
1044          * reference to reach 0 isn't an application bug anyway.
1045          */
1046         destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1047         
1048 #ifdef DEBUG_REFS
1049         g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1050                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1051                    handle,
1052                    _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1053 #endif
1054         
1055         if(destroy==TRUE) {
1056                 /* Need to copy the handle info, reset the slot in the
1057                  * array, and _only then_ call the close function to
1058                  * avoid race conditions (eg file descriptors being
1059                  * closed, and another file being opened getting the
1060                  * same fd racing the memset())
1061                  */
1062                 struct _WapiHandleUnshared handle_data;
1063                 struct _WapiHandleShared shared_handle_data;
1064                 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1065                 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1066                 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1067
1068                 if (is_shared) {
1069                         /* If this is a shared handle we need to take
1070                          * the shared lock outside of the scan_mutex
1071                          * lock to avoid deadlocks
1072                          */
1073                         thr_ret = _wapi_handle_lock_shared_handles ();
1074                         g_assert (thr_ret == 0);
1075                 }
1076                 
1077                 thr_ret = mono_os_mutex_lock (&scan_mutex);
1078
1079                 DEBUG ("%s: Destroying handle %p", __func__, handle);
1080                 
1081                 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1082                         sizeof (struct _WapiHandleUnshared));
1083
1084                 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1085                         sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1086
1087                 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1088                 
1089                 if (!is_shared) {
1090                         /* Destroy the mutex and cond var.  We hope nobody
1091                          * tried to grab them between the handle unlock and
1092                          * now, but pthreads doesn't have a
1093                          * "unlock_and_destroy" atomic function.
1094                          */
1095                         thr_ret = mono_os_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1096                         /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
1097                         if (thr_ret == EBUSY && ignore_private_busy_handles) {
1098                                 early_exit = TRUE;
1099                         } else {
1100                                 if (thr_ret != 0)
1101                                         g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
1102
1103                                 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1104                                 if (thr_ret == EBUSY && ignore_private_busy_handles)
1105                                         early_exit = TRUE;
1106                                 else if (thr_ret != 0)
1107                                         g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
1108                         }
1109                 } else {
1110                         struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1111
1112                         memcpy (&shared_handle_data, shared,
1113                                 sizeof (struct _WapiHandleShared));
1114                         
1115                         /* It's possible that this handle is already
1116                          * pointing at a deleted shared section
1117                          */
1118 #ifdef DEBUG_REFS
1119                         g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1120 #endif
1121
1122                         if (shared->handle_refs > 0) {
1123                                 shared->handle_refs--;
1124                                 if (shared->handle_refs == 0) {
1125                                         memset (shared, '\0', sizeof (struct _WapiHandleShared));
1126                                 }
1127                         }
1128                 }
1129
1130                 thr_ret = mono_os_mutex_unlock (&scan_mutex);
1131                 g_assert (thr_ret == 0);
1132
1133                 if (early_exit)
1134                         return;
1135                 if (is_shared) {
1136                         _wapi_handle_unlock_shared_handles ();
1137                 }
1138                 
1139                 if (close_func != NULL) {
1140                         if (is_shared) {
1141                                 close_func (handle, &shared_handle_data.u);
1142                         } else {
1143                                 close_func (handle, &handle_data.u);
1144                         }
1145                 }
1146         }
1147 }
1148
1149 void _wapi_handle_unref (gpointer handle)
1150 {
1151         _wapi_handle_unref_full (handle, FALSE);
1152 }
1153
1154 void _wapi_handle_register_capabilities (WapiHandleType type,
1155                                          WapiHandleCapability caps)
1156 {
1157         handle_caps[type] = caps;
1158 }
1159
1160 gboolean _wapi_handle_test_capabilities (gpointer handle,
1161                                          WapiHandleCapability caps)
1162 {
1163         guint32 idx = GPOINTER_TO_UINT(handle);
1164         WapiHandleType type;
1165
1166         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1167                 return(FALSE);
1168         }
1169         
1170         type = _WAPI_PRIVATE_HANDLES(idx).type;
1171
1172         DEBUG ("%s: testing 0x%x against 0x%x (%d)", __func__,
1173                    handle_caps[type], caps, handle_caps[type] & caps);
1174         
1175         return((handle_caps[type] & caps) != 0);
1176 }
1177
1178 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1179 {
1180         if (handle_ops[type] != NULL &&
1181             handle_ops[type]->close != NULL) {
1182                 return (handle_ops[type]->close);
1183         }
1184
1185         return (NULL);
1186 }
1187
1188 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1189 {
1190         guint32 idx = GPOINTER_TO_UINT(handle);
1191         WapiHandleType type;
1192
1193         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1194                 return;
1195         }
1196         
1197         type = _WAPI_PRIVATE_HANDLES(idx).type;
1198
1199         if (handle_ops[type] != NULL &&
1200             handle_ops[type]->close != NULL) {
1201                 handle_ops[type]->close (handle, data);
1202         }
1203 }
1204
1205 void _wapi_handle_ops_signal (gpointer handle)
1206 {
1207         guint32 idx = GPOINTER_TO_UINT(handle);
1208         WapiHandleType type;
1209
1210         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1211                 return;
1212         }
1213         
1214         type = _WAPI_PRIVATE_HANDLES(idx).type;
1215
1216         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1217                 handle_ops[type]->signal (handle);
1218         }
1219 }
1220
1221 gboolean _wapi_handle_ops_own (gpointer handle)
1222 {
1223         guint32 idx = GPOINTER_TO_UINT(handle);
1224         WapiHandleType type;
1225         
1226         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1227                 return(FALSE);
1228         }
1229         
1230         type = _WAPI_PRIVATE_HANDLES(idx).type;
1231
1232         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1233                 return(handle_ops[type]->own_handle (handle));
1234         } else {
1235                 return(FALSE);
1236         }
1237 }
1238
1239 gboolean _wapi_handle_ops_isowned (gpointer handle)
1240 {
1241         guint32 idx = GPOINTER_TO_UINT(handle);
1242         WapiHandleType type;
1243
1244         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1245                 return(FALSE);
1246         }
1247         
1248         type = _WAPI_PRIVATE_HANDLES(idx).type;
1249
1250         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1251                 return(handle_ops[type]->is_owned (handle));
1252         } else {
1253                 return(FALSE);
1254         }
1255 }
1256
1257 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
1258 {
1259         guint32 idx = GPOINTER_TO_UINT(handle);
1260         WapiHandleType type;
1261         
1262         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1263                 return(WAIT_FAILED);
1264         }
1265         
1266         type = _WAPI_PRIVATE_HANDLES(idx).type;
1267         
1268         if (handle_ops[type] != NULL &&
1269             handle_ops[type]->special_wait != NULL) {
1270                 return(handle_ops[type]->special_wait (handle, timeout, alertable));
1271         } else {
1272                 return(WAIT_FAILED);
1273         }
1274 }
1275
1276 void _wapi_handle_ops_prewait (gpointer handle)
1277 {
1278         guint32 idx = GPOINTER_TO_UINT (handle);
1279         WapiHandleType type;
1280         
1281         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1282                 return;
1283         }
1284         
1285         type = _WAPI_PRIVATE_HANDLES (idx).type;
1286         
1287         if (handle_ops[type] != NULL &&
1288             handle_ops[type]->prewait != NULL) {
1289                 handle_ops[type]->prewait (handle);
1290         }
1291 }
1292
1293
1294 /**
1295  * CloseHandle:
1296  * @handle: The handle to release
1297  *
1298  * Closes and invalidates @handle, releasing any resources it
1299  * consumes.  When the last handle to a temporary or non-persistent
1300  * object is closed, that object can be deleted.  Closing the same
1301  * handle twice is an error.
1302  *
1303  * Return value: %TRUE on success, %FALSE otherwise.
1304  */
1305 gboolean CloseHandle(gpointer handle)
1306 {
1307         if (handle == NULL) {
1308                 /* Problem: because we map file descriptors to the
1309                  * same-numbered handle we can't tell the difference
1310                  * between a bogus handle and the handle to stdin.
1311                  * Assume that it's the console handle if that handle
1312                  * exists...
1313                  */
1314                 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1315                         SetLastError (ERROR_INVALID_PARAMETER);
1316                         return(FALSE);
1317                 }
1318         }
1319         if (handle == _WAPI_HANDLE_INVALID){
1320                 SetLastError (ERROR_INVALID_PARAMETER);
1321                 return(FALSE);
1322         }
1323         
1324         _wapi_handle_unref (handle);
1325         
1326         return(TRUE);
1327 }
1328
1329 /* Lots more to implement here, but this is all we need at the moment */
1330 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1331                           gpointer targetprocess, gpointer *target,
1332                           guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1333 {
1334         if (srcprocess != _WAPI_PROCESS_CURRENT ||
1335             targetprocess != _WAPI_PROCESS_CURRENT) {
1336                 /* Duplicating other process's handles is not supported */
1337                 SetLastError (ERROR_INVALID_HANDLE);
1338                 return(FALSE);
1339         }
1340         
1341         if (src == _WAPI_PROCESS_CURRENT) {
1342                 *target = _wapi_process_duplicate ();
1343         } else if (src == _WAPI_THREAD_CURRENT) {
1344                 g_assert_not_reached ();
1345         } else {
1346                 _wapi_handle_ref (src);
1347                 *target = src;
1348         }
1349         
1350         return(TRUE);
1351 }
1352
1353 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1354                                                gpointer *handles,
1355                                                gboolean waitall,
1356                                                guint32 *retcount,
1357                                                guint32 *lowest)
1358 {
1359         guint32 count, i, iter=0;
1360         gboolean ret;
1361         int thr_ret;
1362         WapiHandleType type;
1363         
1364         /* Lock all the handles, with backoff */
1365 again:
1366         thr_ret = _wapi_handle_lock_shared_handles ();
1367         g_assert (thr_ret == 0);
1368         
1369         for(i=0; i<numhandles; i++) {
1370                 gpointer handle = handles[i];
1371                 guint32 idx = GPOINTER_TO_UINT(handle);
1372
1373                 DEBUG ("%s: attempting to lock %p", __func__, handle);
1374
1375                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1376
1377                 thr_ret = _wapi_handle_trylock_handle (handle);
1378                 
1379                 if (thr_ret != 0) {
1380                         /* Bummer */
1381                         
1382                         DEBUG ("%s: attempt failed for %p: %s", __func__,
1383                                    handle, strerror (thr_ret));
1384
1385                         thr_ret = _wapi_handle_unlock_shared_handles ();
1386                         g_assert (thr_ret == 0);
1387                         
1388                         while (i--) {
1389                                 handle = handles[i];
1390                                 idx = GPOINTER_TO_UINT(handle);
1391
1392                                 thr_ret = _wapi_handle_unlock_handle (handle);
1393                                 g_assert (thr_ret == 0);
1394                         }
1395
1396                         /* If iter ever reaches 100 the nanosleep will
1397                          * return EINVAL immediately, but we have a
1398                          * design flaw if that happens.
1399                          */
1400                         iter++;
1401                         if(iter==100) {
1402                                 g_warning ("%s: iteration overflow!",
1403                                            __func__);
1404                                 iter=1;
1405                         }
1406                         
1407                         DEBUG ("%s: Backing off for %d ms", __func__,
1408                                    iter*10);
1409                         _wapi_handle_spin (10 * iter);
1410                         
1411                         goto again;
1412                 }
1413         }
1414         
1415         DEBUG ("%s: Locked all handles", __func__);
1416
1417         count=0;
1418         *lowest=numhandles;
1419         
1420         for(i=0; i<numhandles; i++) {
1421                 gpointer handle = handles[i];
1422                 guint32 idx = GPOINTER_TO_UINT(handle);
1423                 
1424                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1425
1426                 DEBUG ("%s: Checking handle %p", __func__, handle);
1427
1428                 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1429                     (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1430                    (_WAPI_SHARED_HANDLE(type) &&
1431                     WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1432                    (!_WAPI_SHARED_HANDLE(type) &&
1433                     _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1434                         count++;
1435                         
1436                         DEBUG ("%s: Handle %p signalled", __func__,
1437                                    handle);
1438                         if(*lowest>i) {
1439                                 *lowest=i;
1440                         }
1441                 }
1442         }
1443         
1444         DEBUG ("%s: %d event handles signalled", __func__, count);
1445
1446         if ((waitall == TRUE && count == numhandles) ||
1447             (waitall == FALSE && count > 0)) {
1448                 ret=TRUE;
1449         } else {
1450                 ret=FALSE;
1451         }
1452         
1453         DEBUG ("%s: Returning %d", __func__, ret);
1454
1455         *retcount=count;
1456         
1457         return(ret);
1458 }
1459
1460 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1461 {
1462         guint32 i;
1463         int thr_ret;
1464         
1465         thr_ret = _wapi_handle_unlock_shared_handles ();
1466         g_assert (thr_ret == 0);
1467         
1468         for(i=0; i<numhandles; i++) {
1469                 gpointer handle = handles[i];
1470                 
1471                 DEBUG ("%s: unlocking handle %p", __func__, handle);
1472
1473                 thr_ret = _wapi_handle_unlock_handle (handle);
1474                 g_assert (thr_ret == 0);
1475         }
1476 }
1477
1478 int
1479 _wapi_handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
1480 {
1481         return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll, alerted);
1482 }
1483
1484 static void
1485 signal_handle_and_unref (gpointer handle)
1486 {
1487         pthread_cond_t *cond;
1488         mono_mutex_t *mutex;
1489         guint32 idx;
1490
1491         g_assert (handle);
1492
1493         /* If we reach here, then interrupt token is set to the flag value, which
1494          * means that the target thread is either
1495          * - before the first CAS in timedwait, which means it won't enter the wait.
1496          * - it is after the first CAS, so it is already waiting, or it will enter
1497          *    the wait, and it will be interrupted by the broadcast. */
1498         idx = GPOINTER_TO_UINT (handle);
1499         cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1500         mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1501
1502         mono_os_mutex_lock (mutex);
1503         mono_os_cond_broadcast (cond);
1504         mono_os_mutex_unlock (mutex);
1505
1506         _wapi_handle_unref (handle);
1507 }
1508
1509 int
1510 _wapi_handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean alertable, gboolean poll, gboolean *alerted)
1511 {
1512         DEBUG ("%s: waiting for %p (type %s)", __func__, handle,
1513                    _wapi_handle_typename[_wapi_handle_type (handle)]);
1514
1515         if (alertable)
1516                 g_assert (alerted);
1517
1518         if (alerted)
1519                 *alerted = FALSE;
1520
1521         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1522                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1523                         return (0);
1524                 }
1525                 if (timeout != INFINITE) {
1526                         if (timeout < 100) {
1527                                 /* FIXME: Real timeout is less than
1528                                  * 100ms time, but is it really worth
1529                                  * calculating to the exact ms?
1530                                  */
1531                                 _wapi_handle_spin (100);
1532
1533                                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1534                                         return (0);
1535                                 } else {
1536                                         return (ETIMEDOUT);
1537                                 }
1538                         }
1539                 }
1540                 _wapi_handle_spin (100);
1541                 return (0);
1542                 
1543         } else {
1544                 guint32 idx = GPOINTER_TO_UINT(handle);
1545                 int res;
1546                 pthread_cond_t *cond;
1547                 mono_mutex_t *mutex;
1548
1549                 if (alertable) {
1550                         mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
1551                         if (*alerted)
1552                                 return 0;
1553                         _wapi_handle_ref (handle);
1554                 }
1555
1556                 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1557                 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1558
1559                 if (!poll) {
1560                         res = mono_os_cond_timedwait (cond, mutex, timeout);
1561                 } else {
1562                         /* This is needed when waiting for process handles */
1563                         if (!alertable) {
1564                                 /*
1565                                  * pthread_cond_(timed)wait() can return 0 even if the condition was not
1566                                  * signalled.  This happens at least on Darwin.  We surface this, i.e., we
1567                                  * get spurious wake-ups.
1568                                  *
1569                                  * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
1570                                  */
1571                                 res = mono_os_cond_timedwait (cond, mutex, timeout);
1572                         } else {
1573                                 if (timeout < 100) {
1574                                         /* Real timeout is less than 100ms time */
1575                                         res = mono_os_cond_timedwait (cond, mutex, timeout);
1576                                 } else {
1577                                         res = mono_os_cond_timedwait (cond, mutex, 100);
1578
1579                                         /* Mask the fake timeout, this will cause
1580                                          * another poll if the cond was not really signaled
1581                                          */
1582                                         if (res == ETIMEDOUT)
1583                                                 res = 0;
1584                                 }
1585                         }
1586                 }
1587
1588                 if (alertable) {
1589                         mono_thread_info_uninstall_interrupt (alerted);
1590                         if (!*alerted) {
1591                                 /* if it is alerted, then the handle is unref in the interrupt callback */
1592                                 _wapi_handle_unref (handle);
1593                         }
1594                 }
1595
1596                 return res;
1597         }
1598 }
1599
1600 void
1601 _wapi_free_share_info (_WapiFileShare *share_info)
1602 {
1603         file_share_hash_lock ();
1604         g_hash_table_remove (file_share_hash, share_info);
1605         file_share_hash_unlock ();
1606         /* The hashtable dtor frees share_info */
1607 }
1608
1609 static gint
1610 wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
1611 {
1612         const _WapiFileShare *s1 = (const _WapiFileShare *)ka;
1613         const _WapiFileShare *s2 = (const _WapiFileShare *)kb;
1614
1615         return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
1616 }
1617
1618 static guint
1619 wapi_share_info_hash (gconstpointer data)
1620 {
1621         const _WapiFileShare *s = (const _WapiFileShare *)data;
1622
1623         return s->inode;
1624 }
1625
1626 gboolean _wapi_handle_get_or_set_share (guint64 device, guint64 inode,
1627                                         guint32 new_sharemode,
1628                                         guint32 new_access,
1629                                         guint32 *old_sharemode,
1630                                         guint32 *old_access,
1631                                         struct _WapiFileShare **share_info)
1632 {
1633         struct _WapiFileShare *file_share;
1634         int thr_ret;
1635         gboolean exists = FALSE;
1636
1637         /* Prevents entries from expiring under us as we search
1638          */
1639         thr_ret = _wapi_handle_lock_shared_handles ();
1640         g_assert (thr_ret == 0);
1641         
1642         /* Prevent new entries racing with us */
1643         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1644         g_assert (thr_ret == 0);
1645
1646         _WapiFileShare tmp;
1647
1648         /*
1649          * Instead of allocating a 4MB array, we use a hash table to keep track of this
1650          * info. This is needed even if SHM is disabled, to track sharing inside
1651          * the current process.
1652          */
1653         if (!file_share_hash) {
1654                 file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
1655                 mono_os_mutex_init_recursive (&file_share_hash_mutex);
1656         }
1657
1658         tmp.device = device;
1659         tmp.inode = inode;
1660
1661         file_share_hash_lock ();
1662
1663         file_share = (_WapiFileShare *)g_hash_table_lookup (file_share_hash, &tmp);
1664         if (file_share) {
1665                 *old_sharemode = file_share->sharemode;
1666                 *old_access = file_share->access;
1667                 *share_info = file_share;
1668
1669                 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1670                 exists = TRUE;
1671         } else {
1672                 file_share = g_new0 (_WapiFileShare, 1);
1673
1674                 file_share->device = device;
1675                 file_share->inode = inode;
1676                 file_share->opened_by_pid = _wapi_getpid ();
1677                 file_share->sharemode = new_sharemode;
1678                 file_share->access = new_access;
1679                 file_share->handle_refs = 1;
1680                 *share_info = file_share;
1681
1682                 g_hash_table_insert (file_share_hash, file_share, file_share);
1683         }
1684
1685         file_share_hash_unlock ();
1686         
1687         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1688
1689         _wapi_handle_unlock_shared_handles ();
1690
1691         return(exists);
1692 }
1693
1694 /* If we don't have the info in /proc, check if the process that
1695  * opened this share info is still there (it's not a perfect method,
1696  * due to pid reuse)
1697  */
1698 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1699 {
1700 #if defined(__native_client__)
1701         g_assert_not_reached ();
1702 #elif defined(HAVE_KILL)
1703         if (kill (share_info->opened_by_pid, 0) == -1 &&
1704             (errno == ESRCH ||
1705              errno == EPERM)) {
1706                 /* It's gone completely (or there's a new process
1707                  * owned by someone else) so mark this share info as
1708                  * dead
1709                  */
1710                 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1711
1712                 _wapi_free_share_info (share_info);
1713         }
1714 #endif
1715 }
1716
1717 #ifdef __linux__
1718 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1719  * question.  If there are none, reset the share info.
1720  *
1721  * This implementation is Linux-specific; legacy systems will have to
1722  * implement their own ways of finding out if a particular file is
1723  * open by a process.
1724  */
1725 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1726 {
1727         gboolean found = FALSE, proc_fds = FALSE;
1728         int thr_ret, i;
1729         
1730         /* Prevents entries from expiring under us if we remove this
1731          * one
1732          */
1733         thr_ret = _wapi_handle_lock_shared_handles ();
1734         g_assert (thr_ret == 0);
1735         
1736         /* Prevent new entries racing with us */
1737         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1738         g_assert (thr_ret == 0);
1739         
1740         /* If there is no /proc, there's nothing more we can do here */
1741         if (access ("/proc", F_OK) == -1) {
1742                 _wapi_handle_check_share_by_pid (share_info);
1743                 goto done;
1744         }
1745
1746         /* If there's another handle that thinks it owns this fd, then even
1747          * if the fd has been closed behind our back consider it still owned.
1748          * See bugs 75764 and 75891
1749          */
1750         for (i = 0; i < _wapi_fd_reserve; i++) {
1751                 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1752                         struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1753
1754                         if (i != fd &&
1755                                 handle->type == WAPI_HANDLE_FILE) {
1756                                 struct _WapiHandle_file *file_handle = &handle->u.file;
1757
1758                                 if (file_handle->share_info == share_info) {
1759                                         DEBUG ("%s: handle 0x%x has this file open!",
1760                                                            __func__, i);
1761
1762                                         goto done;
1763                                 }
1764                         }
1765                 }
1766         }
1767
1768         if (proc_fds == FALSE) {
1769                 _wapi_handle_check_share_by_pid (share_info);
1770         } else if (found == FALSE) {
1771                 /* Blank out this entry, as it is stale */
1772                 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1773
1774                 _wapi_free_share_info (share_info);
1775         }
1776
1777 done:
1778         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1779
1780         _wapi_handle_unlock_shared_handles ();
1781 }
1782 #else
1783 //
1784 // Other implementations (non-Linux)
1785 //
1786 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1787 {
1788         int thr_ret;
1789         
1790         /* Prevents entries from expiring under us if we remove this
1791          * one */
1792         thr_ret = _wapi_handle_lock_shared_handles ();
1793         g_assert (thr_ret == 0);
1794         
1795         /* Prevent new entries racing with us */
1796         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1797         g_assert (thr_ret == 0);
1798         
1799         _wapi_handle_check_share_by_pid (share_info);
1800
1801         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1802         _wapi_handle_unlock_shared_handles ();
1803 }
1804 #endif
1805
1806 void _wapi_handle_dump (void)
1807 {
1808         struct _WapiHandleUnshared *handle_data;
1809         guint32 i, k;
1810         int thr_ret;
1811         
1812         thr_ret = mono_os_mutex_lock (&scan_mutex);
1813         g_assert (thr_ret == 0);
1814         
1815         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1816                 if (_wapi_private_handles [i]) {
1817                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1818                                 handle_data = &_wapi_private_handles [i][k];
1819
1820                                 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1821                                         continue;
1822                                 }
1823                 
1824                                 g_print ("%3x [%7s] %s %d ",
1825                                                  i * _WAPI_HANDLE_INITIAL_COUNT + k,
1826                                                  _wapi_handle_typename[handle_data->type],
1827                                                  handle_data->signalled?"Sg":"Un",
1828                                                  handle_data->ref);
1829                                 if (handle_details[handle_data->type])
1830                                         handle_details[handle_data->type](&handle_data->u);
1831                                 g_print ("\n");
1832                         }
1833                 }
1834         }
1835
1836         thr_ret = mono_os_mutex_unlock (&scan_mutex);
1837         g_assert (thr_ret == 0);
1838 }
1839
1840 static void _wapi_shared_details (gpointer handle_info)
1841 {
1842         struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1843         
1844         g_print ("offset: 0x%x", shared->offset);
1845 }