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