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