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