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