[io-layer] Merge _WapiHandleShared type into _WapiHandleUnshared
[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 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 _WapiHandleUnshared *handle,
277                                       WapiHandleType type,
278                                       gpointer handle_specific)
279 {
280         g_assert (_wapi_has_shut_down == FALSE);
281         
282         handle->type = type;
283         handle->signalled = FALSE;
284         handle->ref = 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 _WapiHandleUnshared *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 {
543         guint32 handle_idx = 0;
544         gpointer handle = INVALID_HANDLE_VALUE;
545         int thr_ret, i, k;
546         struct _WapiHandleUnshared *shared;
547         
548         g_assert (_wapi_has_shut_down == FALSE);
549         
550         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating new handle of type %s to offset %d", __func__,
551                    _wapi_handle_typename[type], offset);
552
553         g_assert(!_WAPI_FD_HANDLE(type));
554         g_assert(_WAPI_SHARED_HANDLE(type));
555         g_assert(offset != 0);
556
557         shared = &_wapi_shared_layout->handles[offset];
558                 
559         thr_ret = mono_os_mutex_lock (&scan_mutex);
560         g_assert (thr_ret == 0);
561
562         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
563                 if (_wapi_private_handles [i]) {
564                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
565                                 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
566                 
567                                 if (handle_data->type == type &&
568                                         handle_data->u.shared.offset == offset) {
569                                         handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
570                                         goto first_pass_done;
571                                 }
572                         }
573                 }
574         }
575
576 first_pass_done:
577         thr_ret = mono_os_mutex_unlock (&scan_mutex);
578         g_assert (thr_ret == 0);
579
580         if (handle != INVALID_HANDLE_VALUE) {
581                 _wapi_handle_ref (handle);
582
583                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning old handle %p referencing 0x%x",
584                            __func__, handle, offset);
585                 return (handle);
586         }
587
588         /* Prevent entries expiring under us as we search */
589         thr_ret = _wapi_handle_lock_shared_handles ();
590         g_assert (thr_ret == 0);
591         
592         if (shared->type == WAPI_HANDLE_UNUSED) {
593                 /* Someone deleted this handle while we were working */
594                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle at 0x%x unused", __func__, offset);
595                 goto done;
596         }
597
598         if (shared->type != type) {
599                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Wrong type at %d 0x%x! Found %s wanted %s",
600                            __func__, offset, offset,
601                            _wapi_handle_typename[shared->type],
602                            _wapi_handle_typename[type]);
603                 goto done;
604         }
605         
606         thr_ret = mono_os_mutex_lock (&scan_mutex);
607         g_assert (thr_ret == 0);
608         
609         while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
610                 /* Try and expand the array, and have another go */
611                 int idx = SLOT_INDEX (_wapi_private_handle_count);
612                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
613                                                 _WAPI_HANDLE_INITIAL_COUNT);
614
615                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
616                 _wapi_private_handle_slot_count ++;
617         }
618                 
619         thr_ret = mono_os_mutex_unlock (&scan_mutex);
620         g_assert (thr_ret == 0);
621                 
622         /* Make sure we left the space for fd mappings */
623         g_assert (handle_idx >= _wapi_fd_reserve);
624         
625         handle = GUINT_TO_POINTER (handle_idx);
626                 
627         _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
628         InterlockedIncrement ((gint32 *)&shared->ref);
629         
630         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->ref);
631         
632 done:
633         _wapi_handle_unlock_shared_handles ();
634
635         return(handle);
636 }
637
638 static void
639 init_handles_slot (int idx)
640 {
641         int thr_ret;
642
643         thr_ret = mono_os_mutex_lock (&scan_mutex);
644         g_assert (thr_ret == 0);
645
646         if (_wapi_private_handles [idx] == NULL) {
647                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
648                                                                                           _WAPI_HANDLE_INITIAL_COUNT);
649                 g_assert (_wapi_private_handles [idx]);
650         }
651
652         thr_ret = mono_os_mutex_unlock (&scan_mutex);
653         g_assert (thr_ret == 0);
654 }
655
656 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
657                               gpointer handle_specific)
658 {
659         struct _WapiHandleUnshared *handle;
660         int thr_ret;
661         
662         g_assert (_wapi_has_shut_down == FALSE);
663         
664         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating new handle of type %s", __func__,
665                    _wapi_handle_typename[type]);
666         
667         g_assert(_WAPI_FD_HANDLE(type));
668         g_assert(!_WAPI_SHARED_HANDLE(type));
669         
670         if (fd >= _wapi_fd_reserve) {
671                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d is too big", __func__, fd);
672
673                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
674         }
675
676         /* Initialize the array entries on demand */
677         if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
678                 init_handles_slot (SLOT_INDEX (fd));
679
680         handle = &_WAPI_PRIVATE_HANDLES(fd);
681         
682         if (handle->type != WAPI_HANDLE_UNUSED) {
683                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d is already in use!", __func__, fd);
684                 /* FIXME: clean up this handle?  We can't do anything
685                  * with the fd, cos thats the new one
686                  */
687         }
688
689         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Assigning new fd handle %d", __func__, fd);
690
691         /* Prevent file share entries racing with us, when the file
692          * handle is only half initialised
693          */
694         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
695         g_assert(thr_ret == 0);
696
697         _wapi_handle_init (handle, type, handle_specific);
698
699         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
700
701         return(GUINT_TO_POINTER(fd));
702 }
703
704 gboolean 
705 _wapi_lookup_handle (gpointer handle, WapiHandleType type,
706                               gpointer *handle_specific)
707 {
708         struct _WapiHandleUnshared *handle_data;
709         guint32 handle_idx = GPOINTER_TO_UINT(handle);
710
711         if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
712                 return(FALSE);
713         }
714
715         /* Initialize the array entries on demand */
716         if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
717                 init_handles_slot (SLOT_INDEX (handle_idx));
718         
719         handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
720         
721         if (handle_data->type != type) {
722                 return(FALSE);
723         }
724
725         if (handle_specific == NULL) {
726                 return(FALSE);
727         }
728         
729         if (_WAPI_SHARED_HANDLE(type)) {
730                 struct _WapiHandle_shared_ref *ref;
731                 struct _WapiHandleUnshared *shared_handle_data;
732                         
733                 ref = &handle_data->u.shared;
734                 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
735                 
736                 if (shared_handle_data->type != type) {
737                         /* The handle must have been deleted on us
738                          */
739                         return (FALSE);
740                 }
741                 
742                 *handle_specific = &shared_handle_data->u;
743         } else {
744                 *handle_specific = &handle_data->u;
745         }
746         
747         return(TRUE);
748 }
749
750 void
751 _wapi_handle_foreach (WapiHandleType type,
752                         gboolean (*on_each)(gpointer test, gpointer user),
753                         gpointer user_data)
754 {
755         struct _WapiHandleUnshared *handle_data = NULL;
756         gpointer ret = NULL;
757         guint32 i, k;
758         int thr_ret;
759
760         thr_ret = mono_os_mutex_lock (&scan_mutex);
761         g_assert (thr_ret == 0);
762
763         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
764                 if (_wapi_private_handles [i]) {
765                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
766                                 handle_data = &_wapi_private_handles [i][k];
767                         
768                                 if (handle_data->type == type) {
769                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
770                                         if (on_each (ret, user_data) == TRUE)
771                                                 break;
772                                 }
773                         }
774                 }
775         }
776
777         thr_ret = mono_os_mutex_unlock (&scan_mutex);
778         g_assert (thr_ret == 0);
779 }
780
781 /* This might list some shared handles twice if they are already
782  * opened by this process, and the check function returns FALSE the
783  * first time.  Shared handles that are created during the search are
784  * unreffed if the check function returns FALSE, so callers must not
785  * rely on the handle persisting (unless the check function returns
786  * TRUE)
787  * The caller owns the returned handle.
788  */
789 gpointer _wapi_search_handle (WapiHandleType type,
790                               gboolean (*check)(gpointer test, gpointer user),
791                               gpointer user_data,
792                               gpointer *handle_specific,
793                               gboolean search_shared)
794 {
795         struct _WapiHandleUnshared *handle_data = NULL;
796         struct _WapiHandleUnshared *shared = NULL;
797         gpointer ret = NULL;
798         guint32 i, k;
799         gboolean found = FALSE;
800         int thr_ret;
801
802         thr_ret = mono_os_mutex_lock (&scan_mutex);
803         g_assert (thr_ret == 0);
804         
805         for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
806                 if (_wapi_private_handles [i]) {
807                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
808                                 handle_data = &_wapi_private_handles [i][k];
809                 
810                                 if (handle_data->type == type) {
811                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
812                                         if (check (ret, user_data) == TRUE) {
813                                                 _wapi_handle_ref (ret);
814                                                 found = TRUE;
815
816                                                 if (_WAPI_SHARED_HANDLE (type)) {
817                                                         shared = &_wapi_shared_layout->handles[i];
818                                                 }
819                                         
820                                                 break;
821                                         }
822                                 }
823                         }
824                 }
825         }
826
827         thr_ret = mono_os_mutex_unlock (&scan_mutex);
828         g_assert (thr_ret == 0);
829
830         if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
831                 /* Not found yet, so search the shared memory too */
832                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Looking at other shared handles...", __func__);
833
834                 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
835                         shared = &_wapi_shared_layout->handles[i];
836                         
837                         if (shared->type == type) {
838                                 /* Tell new_from_offset to not
839                                  * timestamp this handle, because
840                                  * otherwise it will ping every handle
841                                  * in the list and they will never
842                                  * expire
843                                  */
844                                 ret = _wapi_handle_new_from_offset (type, i);
845                                 if (ret == INVALID_HANDLE_VALUE) {
846                                         /* This handle was deleted
847                                          * while we were looking at it
848                                          */
849                                         continue;
850                                 }
851                                 
852                                 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);
853
854                                 /* It's possible that the shared part
855                                  * of this handle has now been blown
856                                  * away (after new_from_offset
857                                  * successfully opened it,) if its
858                                  * timestamp is too old.  The check
859                                  * function needs to be aware of this,
860                                  * and cope if the handle has
861                                  * vanished.
862                                  */
863                                 if (check (ret, user_data) == TRUE) {
864                                         /* Timestamp this handle, but make
865                                          * sure it still exists first
866                                          */
867                                         thr_ret = _wapi_handle_lock_shared_handles ();
868                                         g_assert (thr_ret == 0);
869                                         
870                                         if (shared->type == type) {
871                                                 found = TRUE;
872                                                 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
873                                         
874                                                 _wapi_handle_unlock_shared_handles ();
875                                                 break;
876                                         } else {
877                                                 /* It's been deleted,
878                                                  * so just keep
879                                                  * looking
880                                                  */
881                                                 _wapi_handle_unlock_shared_handles ();
882                                         }
883                                 }
884                                 
885                                 /* This isn't the handle we're looking
886                                  * for, so drop the reference we took
887                                  * in _wapi_handle_new_from_offset ()
888                                  */
889                                 _wapi_handle_unref (ret);
890                         }
891                 }
892         }
893         
894         if (!found) {
895                 ret = NULL;
896                 goto done;
897         }
898         
899         if(handle_specific != NULL) {
900                 if (_WAPI_SHARED_HANDLE(type)) {
901                         g_assert(shared->type == type);
902                         
903                         *handle_specific = &shared->u;
904                 } else {
905                         *handle_specific = &handle_data->u;
906                 }
907         }
908
909 done:
910         return(ret);
911 }
912
913 /* Returns the offset of the metadata array, or -1 on error, or 0 for
914  * not found (0 is not a valid offset)
915  */
916 gint32 _wapi_search_handle_namespace (WapiHandleType type,
917                                       gchar *utf8_name)
918 {
919         struct _WapiHandleUnshared *shared_handle_data;
920         guint32 i;
921         gint32 ret = 0;
922         int thr_ret;
923         
924         g_assert(_WAPI_SHARED_HANDLE(type));
925         
926         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Lookup for handle named [%s] type %s", __func__,
927                    utf8_name, _wapi_handle_typename[type]);
928
929         thr_ret = _wapi_handle_lock_shared_handles ();
930         g_assert (thr_ret == 0);
931         
932         for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
933                 WapiSharedNamespace *sharedns;
934                 
935                 shared_handle_data = &_wapi_shared_layout->handles[i];
936
937                 /* Check mutex, event, semaphore, timer, job and
938                  * file-mapping object names.  So far only mutex,
939                  * semaphore and event are implemented.
940                  */
941                 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
942                         continue;
943                 }
944
945                 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]);
946
947                 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
948                         
949                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is [%s]", __func__, sharedns->name);
950
951                 if (strcmp (sharedns->name, utf8_name) == 0) {
952                         if (shared_handle_data->type != type) {
953                                 /* Its the wrong type, so fail now */
954                                 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]);
955                                 ret = -1;
956                                 goto done;
957                         } else {
958                                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle 0x%x matches name and type", __func__, i);
959                                 ret = i;
960                                 goto done;
961                         }
962                 }
963         }
964
965 done:
966         _wapi_handle_unlock_shared_handles ();
967         
968         return(ret);
969 }
970
971 void _wapi_handle_ref (gpointer handle)
972 {
973         guint32 idx = GPOINTER_TO_UINT(handle);
974         struct _WapiHandleUnshared *handle_data;
975
976         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
977                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Attempting to ref invalid private handle %p", __func__, handle);
978                 return;
979         }
980         
981         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
982                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Attempting to ref unused handle %p", __func__, handle);
983                 return;
984         }
985
986         handle_data = &_WAPI_PRIVATE_HANDLES(idx);
987         
988         InterlockedIncrement ((gint32 *)&handle_data->ref);
989         
990 #ifdef DEBUG_REFS
991         g_message ("%s: %s handle %p ref now %d", __func__, 
992                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
993                    handle,
994                    _WAPI_PRIVATE_HANDLES(idx).ref);
995 #endif
996 }
997
998 /* The handle must not be locked on entry to this function */
999 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
1000 {
1001         guint32 idx = GPOINTER_TO_UINT(handle);
1002         gboolean destroy = FALSE, early_exit = FALSE;
1003         int thr_ret;
1004
1005         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1006                 return;
1007         }
1008         
1009         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1010                 g_warning ("%s: Attempting to unref unused handle %p",
1011                            __func__, handle);
1012                 return;
1013         }
1014
1015         /* Possible race condition here if another thread refs the
1016          * handle between here and setting the type to UNUSED.  I
1017          * could lock a mutex, but I'm not sure that allowing a handle
1018          * reference to reach 0 isn't an application bug anyway.
1019          */
1020         destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1021         
1022 #ifdef DEBUG_REFS
1023         g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1024                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1025                    handle,
1026                    _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1027 #endif
1028         
1029         if(destroy==TRUE) {
1030                 /* Need to copy the handle info, reset the slot in the
1031                  * array, and _only then_ call the close function to
1032                  * avoid race conditions (eg file descriptors being
1033                  * closed, and another file being opened getting the
1034                  * same fd racing the memset())
1035                  */
1036                 struct _WapiHandleUnshared handle_data;
1037                 struct _WapiHandleUnshared shared_handle_data;
1038                 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1039                 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1040                 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1041
1042                 if (is_shared) {
1043                         /* If this is a shared handle we need to take
1044                          * the shared lock outside of the scan_mutex
1045                          * lock to avoid deadlocks
1046                          */
1047                         thr_ret = _wapi_handle_lock_shared_handles ();
1048                         g_assert (thr_ret == 0);
1049                 }
1050                 
1051                 thr_ret = mono_os_mutex_lock (&scan_mutex);
1052
1053                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Destroying handle %p", __func__, handle);
1054                 
1055                 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1056                         sizeof (struct _WapiHandleUnshared));
1057
1058                 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1059                         sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1060
1061                 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1062                 
1063                 if (!is_shared) {
1064                         /* Destroy the mutex and cond var.  We hope nobody
1065                          * tried to grab them between the handle unlock and
1066                          * now, but pthreads doesn't have a
1067                          * "unlock_and_destroy" atomic function.
1068                          */
1069                         thr_ret = mono_os_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1070                         /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
1071                         if (thr_ret == EBUSY && ignore_private_busy_handles) {
1072                                 early_exit = TRUE;
1073                         } else {
1074                                 if (thr_ret != 0)
1075                                         g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
1076
1077                                 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1078                                 if (thr_ret == EBUSY && ignore_private_busy_handles)
1079                                         early_exit = TRUE;
1080                                 else if (thr_ret != 0)
1081                                         g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
1082                         }
1083                 } else {
1084                         struct _WapiHandleUnshared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1085
1086                         memcpy (&shared_handle_data, shared,
1087                                 sizeof (struct _WapiHandleUnshared));
1088                         
1089                         /* It's possible that this handle is already
1090                          * pointing at a deleted shared section
1091                          */
1092 #ifdef DEBUG_REFS
1093                         g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->ref);
1094 #endif
1095
1096                         if (shared->ref > 0) {
1097                                 shared->ref--;
1098                                 if (shared->ref == 0) {
1099                                         memset (shared, '\0', sizeof (struct _WapiHandleUnshared));
1100                                 }
1101                         }
1102                 }
1103
1104                 thr_ret = mono_os_mutex_unlock (&scan_mutex);
1105                 g_assert (thr_ret == 0);
1106
1107                 if (early_exit)
1108                         return;
1109                 if (is_shared) {
1110                         _wapi_handle_unlock_shared_handles ();
1111                 }
1112                 
1113                 if (close_func != NULL) {
1114                         if (is_shared) {
1115                                 close_func (handle, &shared_handle_data.u);
1116                         } else {
1117                                 close_func (handle, &handle_data.u);
1118                         }
1119                 }
1120         }
1121 }
1122
1123 void _wapi_handle_unref (gpointer handle)
1124 {
1125         _wapi_handle_unref_full (handle, FALSE);
1126 }
1127
1128 void _wapi_handle_register_capabilities (WapiHandleType type,
1129                                          WapiHandleCapability caps)
1130 {
1131         handle_caps[type] = caps;
1132 }
1133
1134 gboolean _wapi_handle_test_capabilities (gpointer handle,
1135                                          WapiHandleCapability caps)
1136 {
1137         guint32 idx = GPOINTER_TO_UINT(handle);
1138         WapiHandleType type;
1139
1140         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1141                 return(FALSE);
1142         }
1143         
1144         type = _WAPI_PRIVATE_HANDLES(idx).type;
1145
1146         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing 0x%x against 0x%x (%d)", __func__,
1147                    handle_caps[type], caps, handle_caps[type] & caps);
1148         
1149         return((handle_caps[type] & caps) != 0);
1150 }
1151
1152 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1153 {
1154         if (handle_ops[type] != NULL &&
1155             handle_ops[type]->close != NULL) {
1156                 return (handle_ops[type]->close);
1157         }
1158
1159         return (NULL);
1160 }
1161
1162 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1163 {
1164         guint32 idx = GPOINTER_TO_UINT(handle);
1165         WapiHandleType type;
1166
1167         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1168                 return;
1169         }
1170         
1171         type = _WAPI_PRIVATE_HANDLES(idx).type;
1172
1173         if (handle_ops[type] != NULL &&
1174             handle_ops[type]->close != NULL) {
1175                 handle_ops[type]->close (handle, data);
1176         }
1177 }
1178
1179 void _wapi_handle_ops_signal (gpointer handle)
1180 {
1181         guint32 idx = GPOINTER_TO_UINT(handle);
1182         WapiHandleType type;
1183
1184         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1185                 return;
1186         }
1187         
1188         type = _WAPI_PRIVATE_HANDLES(idx).type;
1189
1190         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1191                 handle_ops[type]->signal (handle);
1192         }
1193 }
1194
1195 gboolean _wapi_handle_ops_own (gpointer handle)
1196 {
1197         guint32 idx = GPOINTER_TO_UINT(handle);
1198         WapiHandleType type;
1199         
1200         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1201                 return(FALSE);
1202         }
1203         
1204         type = _WAPI_PRIVATE_HANDLES(idx).type;
1205
1206         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1207                 return(handle_ops[type]->own_handle (handle));
1208         } else {
1209                 return(FALSE);
1210         }
1211 }
1212
1213 gboolean _wapi_handle_ops_isowned (gpointer handle)
1214 {
1215         guint32 idx = GPOINTER_TO_UINT(handle);
1216         WapiHandleType type;
1217
1218         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1219                 return(FALSE);
1220         }
1221         
1222         type = _WAPI_PRIVATE_HANDLES(idx).type;
1223
1224         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1225                 return(handle_ops[type]->is_owned (handle));
1226         } else {
1227                 return(FALSE);
1228         }
1229 }
1230
1231 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
1232 {
1233         guint32 idx = GPOINTER_TO_UINT(handle);
1234         WapiHandleType type;
1235         
1236         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1237                 return(WAIT_FAILED);
1238         }
1239         
1240         type = _WAPI_PRIVATE_HANDLES(idx).type;
1241         
1242         if (handle_ops[type] != NULL &&
1243             handle_ops[type]->special_wait != NULL) {
1244                 return(handle_ops[type]->special_wait (handle, timeout, alertable));
1245         } else {
1246                 return(WAIT_FAILED);
1247         }
1248 }
1249
1250 void _wapi_handle_ops_prewait (gpointer handle)
1251 {
1252         guint32 idx = GPOINTER_TO_UINT (handle);
1253         WapiHandleType type;
1254         
1255         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1256                 return;
1257         }
1258         
1259         type = _WAPI_PRIVATE_HANDLES (idx).type;
1260         
1261         if (handle_ops[type] != NULL &&
1262             handle_ops[type]->prewait != NULL) {
1263                 handle_ops[type]->prewait (handle);
1264         }
1265 }
1266
1267
1268 /**
1269  * CloseHandle:
1270  * @handle: The handle to release
1271  *
1272  * Closes and invalidates @handle, releasing any resources it
1273  * consumes.  When the last handle to a temporary or non-persistent
1274  * object is closed, that object can be deleted.  Closing the same
1275  * handle twice is an error.
1276  *
1277  * Return value: %TRUE on success, %FALSE otherwise.
1278  */
1279 gboolean CloseHandle(gpointer handle)
1280 {
1281         if (handle == NULL) {
1282                 /* Problem: because we map file descriptors to the
1283                  * same-numbered handle we can't tell the difference
1284                  * between a bogus handle and the handle to stdin.
1285                  * Assume that it's the console handle if that handle
1286                  * exists...
1287                  */
1288                 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1289                         SetLastError (ERROR_INVALID_PARAMETER);
1290                         return(FALSE);
1291                 }
1292         }
1293         if (handle == _WAPI_HANDLE_INVALID){
1294                 SetLastError (ERROR_INVALID_PARAMETER);
1295                 return(FALSE);
1296         }
1297         
1298         _wapi_handle_unref (handle);
1299         
1300         return(TRUE);
1301 }
1302
1303 /* Lots more to implement here, but this is all we need at the moment */
1304 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1305                           gpointer targetprocess, gpointer *target,
1306                           guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1307 {
1308         if (srcprocess != _WAPI_PROCESS_CURRENT ||
1309             targetprocess != _WAPI_PROCESS_CURRENT) {
1310                 /* Duplicating other process's handles is not supported */
1311                 SetLastError (ERROR_INVALID_HANDLE);
1312                 return(FALSE);
1313         }
1314         
1315         if (src == _WAPI_PROCESS_CURRENT) {
1316                 *target = _wapi_process_duplicate ();
1317         } else if (src == _WAPI_THREAD_CURRENT) {
1318                 g_assert_not_reached ();
1319         } else {
1320                 _wapi_handle_ref (src);
1321                 *target = src;
1322         }
1323         
1324         return(TRUE);
1325 }
1326
1327 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1328                                                gpointer *handles,
1329                                                gboolean waitall,
1330                                                guint32 *retcount,
1331                                                guint32 *lowest)
1332 {
1333         guint32 count, i, iter=0;
1334         gboolean ret;
1335         int thr_ret;
1336         WapiHandleType type;
1337         
1338         /* Lock all the handles, with backoff */
1339 again:
1340         thr_ret = _wapi_handle_lock_shared_handles ();
1341         g_assert (thr_ret == 0);
1342         
1343         for(i=0; i<numhandles; i++) {
1344                 gpointer handle = handles[i];
1345                 guint32 idx = GPOINTER_TO_UINT(handle);
1346
1347                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempting to lock %p", __func__, handle);
1348
1349                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1350
1351                 thr_ret = _wapi_handle_trylock_handle (handle);
1352                 
1353                 if (thr_ret != 0) {
1354                         /* Bummer */
1355                         
1356                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt failed for %p: %s", __func__,
1357                                    handle, strerror (thr_ret));
1358
1359                         thr_ret = _wapi_handle_unlock_shared_handles ();
1360                         g_assert (thr_ret == 0);
1361                         
1362                         while (i--) {
1363                                 handle = handles[i];
1364                                 idx = GPOINTER_TO_UINT(handle);
1365
1366                                 thr_ret = _wapi_handle_unlock_handle (handle);
1367                                 g_assert (thr_ret == 0);
1368                         }
1369
1370                         /* If iter ever reaches 100 the nanosleep will
1371                          * return EINVAL immediately, but we have a
1372                          * design flaw if that happens.
1373                          */
1374                         iter++;
1375                         if(iter==100) {
1376                                 g_warning ("%s: iteration overflow!",
1377                                            __func__);
1378                                 iter=1;
1379                         }
1380                         
1381                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Backing off for %d ms", __func__,
1382                                    iter*10);
1383                         _wapi_handle_spin (10 * iter);
1384                         
1385                         goto again;
1386                 }
1387         }
1388         
1389         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locked all handles", __func__);
1390
1391         count=0;
1392         *lowest=numhandles;
1393         
1394         for(i=0; i<numhandles; i++) {
1395                 gpointer handle = handles[i];
1396                 guint32 idx = GPOINTER_TO_UINT(handle);
1397                 
1398                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1399
1400                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Checking handle %p", __func__, handle);
1401
1402                 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1403                     (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1404                    (_WAPI_SHARED_HANDLE(type) &&
1405                     WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1406                    (!_WAPI_SHARED_HANDLE(type) &&
1407                     _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1408                         count++;
1409                         
1410                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %p signalled", __func__,
1411                                    handle);
1412                         if(*lowest>i) {
1413                                 *lowest=i;
1414                         }
1415                 }
1416         }
1417         
1418         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %d event handles signalled", __func__, count);
1419
1420         if ((waitall == TRUE && count == numhandles) ||
1421             (waitall == FALSE && count > 0)) {
1422                 ret=TRUE;
1423         } else {
1424                 ret=FALSE;
1425         }
1426         
1427         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning %d", __func__, ret);
1428
1429         *retcount=count;
1430         
1431         return(ret);
1432 }
1433
1434 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1435 {
1436         guint32 i;
1437         int thr_ret;
1438         
1439         thr_ret = _wapi_handle_unlock_shared_handles ();
1440         g_assert (thr_ret == 0);
1441         
1442         for(i=0; i<numhandles; i++) {
1443                 gpointer handle = handles[i];
1444                 
1445                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handle %p", __func__, handle);
1446
1447                 thr_ret = _wapi_handle_unlock_handle (handle);
1448                 g_assert (thr_ret == 0);
1449         }
1450 }
1451
1452 static void
1453 signal_handle_and_unref (gpointer handle)
1454 {
1455         pthread_cond_t *cond;
1456         mono_mutex_t *mutex;
1457         guint32 idx;
1458
1459         g_assert (handle);
1460
1461         /* If we reach here, then interrupt token is set to the flag value, which
1462          * means that the target thread is either
1463          * - before the first CAS in timedwait, which means it won't enter the wait.
1464          * - it is after the first CAS, so it is already waiting, or it will enter
1465          *    the wait, and it will be interrupted by the broadcast. */
1466         idx = GPOINTER_TO_UINT (handle);
1467         cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1468         mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1469
1470         mono_os_mutex_lock (mutex);
1471         mono_os_cond_broadcast (cond);
1472         mono_os_mutex_unlock (mutex);
1473
1474         _wapi_handle_unref (handle);
1475 }
1476
1477 int
1478 _wapi_handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted)
1479 {
1480         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: waiting for %p (type %s)", __func__, handle,
1481                    _wapi_handle_typename[_wapi_handle_type (handle)]);
1482
1483         if (alerted)
1484                 *alerted = FALSE;
1485
1486         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1487                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1488                         return (0);
1489                 }
1490                 if (timeout != INFINITE) {
1491                         if (timeout < 100) {
1492                                 /* FIXME: Real timeout is less than 100ms time, but is it really worth calculating to the exact ms? */
1493                                 _wapi_handle_spin (100);
1494                                 return WAPI_SHARED_HANDLE_DATA(handle).signalled ? 0 : ETIMEDOUT;
1495                         }
1496                 }
1497
1498                 _wapi_handle_spin (100);
1499                 return (0);
1500         } else {
1501                 guint32 idx = GPOINTER_TO_UINT(handle);
1502                 int res;
1503                 pthread_cond_t *cond;
1504                 mono_mutex_t *mutex;
1505
1506                 if (alerted) {
1507                         mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
1508                         if (*alerted)
1509                                 return 0;
1510                         _wapi_handle_ref (handle);
1511                 }
1512
1513                 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1514                 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1515
1516                 if (!poll) {
1517                         res = mono_os_cond_timedwait (cond, mutex, timeout);
1518                 } else {
1519                         /* This is needed when waiting for process handles */
1520                         if (!alerted) {
1521                                 /*
1522                                  * pthread_cond_(timed)wait() can return 0 even if the condition was not
1523                                  * signalled.  This happens at least on Darwin.  We surface this, i.e., we
1524                                  * get spurious wake-ups.
1525                                  *
1526                                  * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
1527                                  */
1528                                 res = mono_os_cond_timedwait (cond, mutex, timeout);
1529                         } else {
1530                                 if (timeout < 100) {
1531                                         /* Real timeout is less than 100ms time */
1532                                         res = mono_os_cond_timedwait (cond, mutex, timeout);
1533                                 } else {
1534                                         res = mono_os_cond_timedwait (cond, mutex, 100);
1535
1536                                         /* Mask the fake timeout, this will cause
1537                                          * another poll if the cond was not really signaled
1538                                          */
1539                                         if (res == ETIMEDOUT)
1540                                                 res = 0;
1541                                 }
1542                         }
1543                 }
1544
1545                 if (alerted) {
1546                         mono_thread_info_uninstall_interrupt (alerted);
1547                         if (!*alerted) {
1548                                 /* if it is alerted, then the handle is unref in the interrupt callback */
1549                                 _wapi_handle_unref (handle);
1550                         }
1551                 }
1552
1553                 return res;
1554         }
1555 }
1556
1557 void
1558 _wapi_free_share_info (_WapiFileShare *share_info)
1559 {
1560         file_share_hash_lock ();
1561         g_hash_table_remove (file_share_hash, share_info);
1562         file_share_hash_unlock ();
1563         /* The hashtable dtor frees share_info */
1564 }
1565
1566 static gint
1567 wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
1568 {
1569         const _WapiFileShare *s1 = (const _WapiFileShare *)ka;
1570         const _WapiFileShare *s2 = (const _WapiFileShare *)kb;
1571
1572         return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
1573 }
1574
1575 static guint
1576 wapi_share_info_hash (gconstpointer data)
1577 {
1578         const _WapiFileShare *s = (const _WapiFileShare *)data;
1579
1580         return s->inode;
1581 }
1582
1583 gboolean _wapi_handle_get_or_set_share (guint64 device, guint64 inode,
1584                                         guint32 new_sharemode,
1585                                         guint32 new_access,
1586                                         guint32 *old_sharemode,
1587                                         guint32 *old_access,
1588                                         struct _WapiFileShare **share_info)
1589 {
1590         struct _WapiFileShare *file_share;
1591         int thr_ret;
1592         gboolean exists = FALSE;
1593
1594         /* Prevents entries from expiring under us as we search
1595          */
1596         thr_ret = _wapi_handle_lock_shared_handles ();
1597         g_assert (thr_ret == 0);
1598         
1599         /* Prevent new entries racing with us */
1600         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1601         g_assert (thr_ret == 0);
1602
1603         _WapiFileShare tmp;
1604
1605         /*
1606          * Instead of allocating a 4MB array, we use a hash table to keep track of this
1607          * info. This is needed even if SHM is disabled, to track sharing inside
1608          * the current process.
1609          */
1610         if (!file_share_hash) {
1611                 file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
1612                 mono_os_mutex_init_recursive (&file_share_hash_mutex);
1613         }
1614
1615         tmp.device = device;
1616         tmp.inode = inode;
1617
1618         file_share_hash_lock ();
1619
1620         file_share = (_WapiFileShare *)g_hash_table_lookup (file_share_hash, &tmp);
1621         if (file_share) {
1622                 *old_sharemode = file_share->sharemode;
1623                 *old_access = file_share->access;
1624                 *share_info = file_share;
1625
1626                 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1627                 exists = TRUE;
1628         } else {
1629                 file_share = g_new0 (_WapiFileShare, 1);
1630
1631                 file_share->device = device;
1632                 file_share->inode = inode;
1633                 file_share->opened_by_pid = _wapi_getpid ();
1634                 file_share->sharemode = new_sharemode;
1635                 file_share->access = new_access;
1636                 file_share->handle_refs = 1;
1637                 *share_info = file_share;
1638
1639                 g_hash_table_insert (file_share_hash, file_share, file_share);
1640         }
1641
1642         file_share_hash_unlock ();
1643         
1644         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1645
1646         _wapi_handle_unlock_shared_handles ();
1647
1648         return(exists);
1649 }
1650
1651 /* If we don't have the info in /proc, check if the process that
1652  * opened this share info is still there (it's not a perfect method,
1653  * due to pid reuse)
1654  */
1655 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1656 {
1657 #if defined(__native_client__)
1658         g_assert_not_reached ();
1659 #elif defined(HAVE_KILL)
1660         if (kill (share_info->opened_by_pid, 0) == -1 &&
1661             (errno == ESRCH ||
1662              errno == EPERM)) {
1663                 /* It's gone completely (or there's a new process
1664                  * owned by someone else) so mark this share info as
1665                  * dead
1666                  */
1667                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't find it, destroying entry", __func__);
1668
1669                 _wapi_free_share_info (share_info);
1670         }
1671 #endif
1672 }
1673
1674 #ifdef __linux__
1675 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1676  * question.  If there are none, reset the share info.
1677  *
1678  * This implementation is Linux-specific; legacy systems will have to
1679  * implement their own ways of finding out if a particular file is
1680  * open by a process.
1681  */
1682 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1683 {
1684         gboolean found = FALSE, proc_fds = FALSE;
1685         int thr_ret, i;
1686         
1687         /* Prevents entries from expiring under us if we remove this
1688          * one
1689          */
1690         thr_ret = _wapi_handle_lock_shared_handles ();
1691         g_assert (thr_ret == 0);
1692         
1693         /* Prevent new entries racing with us */
1694         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1695         g_assert (thr_ret == 0);
1696         
1697         /* If there is no /proc, there's nothing more we can do here */
1698         if (access ("/proc", F_OK) == -1) {
1699                 _wapi_handle_check_share_by_pid (share_info);
1700                 goto done;
1701         }
1702
1703         /* If there's another handle that thinks it owns this fd, then even
1704          * if the fd has been closed behind our back consider it still owned.
1705          * See bugs 75764 and 75891
1706          */
1707         for (i = 0; i < _wapi_fd_reserve; i++) {
1708                 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1709                         struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1710
1711                         if (i != fd &&
1712                                 handle->type == WAPI_HANDLE_FILE) {
1713                                 struct _WapiHandle_file *file_handle = &handle->u.file;
1714
1715                                 if (file_handle->share_info == share_info) {
1716                                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle 0x%x has this file open!",
1717                                                            __func__, i);
1718
1719                                         goto done;
1720                                 }
1721                         }
1722                 }
1723         }
1724
1725         if (proc_fds == FALSE) {
1726                 _wapi_handle_check_share_by_pid (share_info);
1727         } else if (found == FALSE) {
1728                 /* Blank out this entry, as it is stale */
1729                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't find it, destroying entry", __func__);
1730
1731                 _wapi_free_share_info (share_info);
1732         }
1733
1734 done:
1735         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1736
1737         _wapi_handle_unlock_shared_handles ();
1738 }
1739 #else
1740 //
1741 // Other implementations (non-Linux)
1742 //
1743 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1744 {
1745         int thr_ret;
1746         
1747         /* Prevents entries from expiring under us if we remove this
1748          * one */
1749         thr_ret = _wapi_handle_lock_shared_handles ();
1750         g_assert (thr_ret == 0);
1751         
1752         /* Prevent new entries racing with us */
1753         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1754         g_assert (thr_ret == 0);
1755         
1756         _wapi_handle_check_share_by_pid (share_info);
1757
1758         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1759         _wapi_handle_unlock_shared_handles ();
1760 }
1761 #endif
1762
1763 void _wapi_handle_dump (void)
1764 {
1765         struct _WapiHandleUnshared *handle_data;
1766         guint32 i, k;
1767         int thr_ret;
1768         
1769         thr_ret = mono_os_mutex_lock (&scan_mutex);
1770         g_assert (thr_ret == 0);
1771         
1772         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1773                 if (_wapi_private_handles [i]) {
1774                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1775                                 handle_data = &_wapi_private_handles [i][k];
1776
1777                                 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1778                                         continue;
1779                                 }
1780                 
1781                                 g_print ("%3x [%7s] %s %d ",
1782                                                  i * _WAPI_HANDLE_INITIAL_COUNT + k,
1783                                                  _wapi_handle_typename[handle_data->type],
1784                                                  handle_data->signalled?"Sg":"Un",
1785                                                  handle_data->ref);
1786                                 if (handle_details[handle_data->type])
1787                                         handle_details[handle_data->type](&handle_data->u);
1788                                 g_print ("\n");
1789                         }
1790                 }
1791         }
1792
1793         thr_ret = mono_os_mutex_unlock (&scan_mutex);
1794         g_assert (thr_ret == 0);
1795 }
1796
1797 static void _wapi_shared_details (gpointer handle_info)
1798 {
1799         struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1800         
1801         g_print ("offset: 0x%x", shared->offset);
1802 }