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