2c30611d91bae6f8205f9b8fe47ae6929afe9133
[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 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <errno.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <sys/un.h>
19 #include <sys/mman.h>
20 #include <dirent.h>
21 #include <sys/stat.h>
22
23 #include <mono/os/gc_wrapper.h>
24
25 #include <mono/io-layer/wapi.h>
26 #include <mono/io-layer/wapi-private.h>
27 #include <mono/io-layer/handles-private.h>
28 #include <mono/io-layer/mono-mutex.h>
29 #include <mono/io-layer/misc-private.h>
30 #include <mono/io-layer/shared.h>
31 #include <mono/io-layer/collection.h>
32
33 #undef DEBUG
34 #undef DEBUG_REFS
35
36 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
37 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
38         NULL,
39         &_wapi_file_ops,
40         &_wapi_console_ops,
41         &_wapi_thread_ops,
42         &_wapi_sem_ops,
43         &_wapi_mutex_ops,
44         &_wapi_event_ops,
45         &_wapi_socket_ops,
46         &_wapi_find_ops,
47         &_wapi_process_ops,
48         &_wapi_pipe_ops,
49         &_wapi_namedmutex_ops,
50 };
51
52 static void _wapi_shared_details (gpointer handle_info);
53
54 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
55         NULL,
56         _wapi_file_details,
57         _wapi_console_details,
58         _wapi_shared_details,   /* thread */
59         _wapi_sem_details,
60         _wapi_mutex_details,
61         _wapi_event_details,
62         NULL,                   /* Nothing useful to see in a socket handle */
63         NULL,                   /* Nothing useful to see in a find handle */
64         _wapi_shared_details,   /* process */
65         _wapi_pipe_details,
66         _wapi_shared_details,   /* namedmutex */
67 };
68
69 const char *_wapi_handle_typename[] = {
70         "Unused",
71         "File",
72         "Console",
73         "Thread",
74         "Sem",
75         "Mutex",
76         "Event",
77         "Socket",
78         "Find",
79         "Process",
80         "Pipe",
81         "N.Mutex",
82         "Error!!"
83 };
84
85 struct _WapiHandleUnshared *_wapi_private_handles = NULL;
86 static guint32 _wapi_private_handle_count = 0;
87
88 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
89 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
90
91 guint32 _wapi_fd_reserve;
92
93 mono_mutex_t _wapi_global_signal_mutex;
94 pthread_cond_t _wapi_global_signal_cond;
95
96 static mono_once_t shared_init_once = MONO_ONCE_INIT;
97 static void shared_init (void)
98 {
99         int thr_ret;
100         
101         _wapi_fd_reserve = getdtablesize();
102
103         _wapi_private_handle_count = _WAPI_HANDLE_INITIAL_COUNT;
104         
105         while(_wapi_fd_reserve > _wapi_private_handle_count) {
106                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
107         }
108         
109         _wapi_private_handles = g_new0 (struct _WapiHandleUnshared,
110                                         _wapi_private_handle_count);
111
112
113         _wapi_shared_layout = _wapi_shm_attach ();
114         g_assert (_wapi_shared_layout != NULL);
115         
116         _wapi_fileshare_layout = _wapi_fileshare_shm_attach ();
117         g_assert (_wapi_fileshare_layout != NULL);
118         
119         _wapi_collection_init ();
120         
121         thr_ret = pthread_cond_init(&_wapi_global_signal_cond, NULL);
122         g_assert (thr_ret == 0);
123         
124         thr_ret = mono_mutex_init(&_wapi_global_signal_mutex, NULL);
125         g_assert (thr_ret == 0);
126 }
127
128 static void _wapi_handle_init_shared_metadata (struct _WapiHandleSharedMetadata *meta)
129 {
130         meta->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
131         meta->signalled = FALSE;
132 }
133
134 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
135                                       WapiHandleType type,
136                                       gpointer handle_specific)
137 {
138         handle->type = type;
139         handle->stale = FALSE;
140         
141         if (handle_specific != NULL) {
142                 memcpy (&handle->u, handle_specific, sizeof (handle->u));
143         }
144 }
145
146 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
147                                WapiHandleType type, gpointer handle_specific)
148 {
149         int thr_ret;
150         
151         handle->type = type;
152         handle->signalled = FALSE;
153         handle->ref = 1;
154         
155         if (!_WAPI_SHARED_HANDLE(type)) {
156                 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
157                 g_assert (thr_ret == 0);
158                                 
159                 thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
160                 g_assert (thr_ret == 0);
161
162                 if (handle_specific != NULL) {
163                         memcpy (&handle->u, handle_specific,
164                                 sizeof (handle->u));
165                 }
166         }
167 }
168
169 static guint32 _wapi_handle_new_shared_offset (guint32 offset)
170 {
171         guint32 i;
172         static guint32 last = 1;
173         
174 again:
175         /* FIXME: expandable array */
176         /* leave a few slots at the end so that there's always space
177          * to move a handle.  (We leave the space in the offset table
178          * too, so we don't have to keep track of inter-segment
179          * offsets.)
180          */
181         for(i = last; i <_WAPI_HANDLE_INITIAL_COUNT - _WAPI_HEADROOM; i++) {
182                 struct _WapiHandleSharedMetadata *meta = &_wapi_shared_layout->metadata[i];
183                 
184                 if(meta->offset == 0) {
185                         if (InterlockedCompareExchange (&meta->offset, offset,
186                                                         0) == 0) {
187                                 last = i + 1;
188                         
189                                 _wapi_handle_init_shared_metadata (meta);
190                                 return(i);
191                         } else {
192                                 /* Someone else beat us to it, just
193                                  * continue looking
194                                  */
195                         }
196                 }
197         }
198
199         if(last > 1) {
200                 /* Try again from the beginning */
201                 last = 1;
202                 goto again;
203         }
204
205         /* Will need to expand the array.  The caller will sort it out */
206
207         return(0);
208 }
209
210 static guint32 _wapi_handle_new_shared (WapiHandleType type,
211                                         gpointer handle_specific)
212 {
213         guint32 offset;
214         static guint32 last = 1;
215         
216         /* The shared memory holds an offset to the real data, so we
217          * can update the handle RCU-style without taking a lock.
218          * This function just allocates the next available data slot,
219          * use _wapi_handle_new_shared_offset to get the offset entry.
220          */
221
222         /* Leave the first slot empty as a guard */
223 again:
224         /* FIXME: expandable array */
225         /* Leave a few slots at the end so that there's always space
226          * to move a handle
227          */
228         for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT - _WAPI_HEADROOM;
229             offset++) {
230                 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
231                 
232                 if(handle->type == WAPI_HANDLE_UNUSED) {
233                         if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
234                                 last = offset + 1;
235                         
236                                 _wapi_handle_init_shared (handle, type,
237                                                           handle_specific);
238                                 return(offset);
239                         } else {
240                                 /* Someone else beat us to it, just
241                                  * continue looking
242                                  */
243                         }
244                 }
245         }
246
247         if(last > 1) {
248                 /* Try again from the beginning */
249                 last = 1;
250                 goto again;
251         }
252
253         /* Will need to expand the array.  The caller will sort it out */
254
255         return(0);
256 }
257
258 /*
259  * _wapi_handle_new_internal:
260  * @type: Init handle to this type
261  *
262  * Search for a free handle and initialize it. Return the handle on
263  * success and 0 on failure.  This is only called from
264  * _wapi_handle_new, and scan_mutex must be held.
265  */
266 static guint32 _wapi_handle_new_internal (WapiHandleType type,
267                                           gpointer handle_specific)
268 {
269         guint32 i;
270         static guint32 last = 0;
271         
272         /* A linear scan should be fast enough.  Start from the last
273          * allocation, assuming that handles are allocated more often
274          * than they're freed. Leave the space reserved for file
275          * descriptors
276          */
277         
278         if (last < _wapi_fd_reserve) {
279                 last = _wapi_fd_reserve;
280         }
281         
282 again:
283         for(i = last; i <_wapi_private_handle_count; i++) {
284                 struct _WapiHandleUnshared *handle = &_wapi_private_handles[i];
285                 
286                 if(handle->type == WAPI_HANDLE_UNUSED) {
287                         last = i + 1;
288                         
289                         _wapi_handle_init (handle, type, handle_specific);
290                         return(i);
291                 }
292         }
293
294         if(last > _wapi_fd_reserve) {
295                 /* Try again from the beginning */
296                 last = _wapi_fd_reserve;
297                 goto again;
298         }
299
300         /* Will need to expand the array.  The caller will sort it out */
301
302         return(0);
303 }
304
305 gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
306 {
307         static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
308         guint32 handle_idx = 0;
309         gpointer handle;
310         int thr_ret;
311         
312         mono_once (&shared_init_once, shared_init);
313         
314 #ifdef DEBUG
315         g_message ("%s: Creating new handle of type %s", __func__,
316                    _wapi_handle_typename[type]);
317 #endif
318
319         g_assert(!_WAPI_FD_HANDLE(type));
320         
321         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
322                               (void *)&scan_mutex);
323         thr_ret = mono_mutex_lock (&scan_mutex);
324         g_assert (thr_ret == 0);
325                 
326         while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
327                 /* Try and expand the array, and have another go */
328                 _wapi_private_handles = g_renew (struct _WapiHandleUnshared,
329                                                  _wapi_private_handles,
330                                                  _wapi_private_handle_count +
331                                                  _WAPI_HANDLE_INITIAL_COUNT);
332                 memset (_wapi_private_handles +
333                         (_wapi_private_handle_count *
334                          sizeof(struct _WapiHandleUnshared)), '\0',
335                         (_WAPI_HANDLE_INITIAL_COUNT *
336                          sizeof(struct _WapiHandleUnshared)));
337                 
338                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
339         }
340                 
341         thr_ret = mono_mutex_unlock (&scan_mutex);
342         g_assert (thr_ret == 0);
343         pthread_cleanup_pop (0);
344                 
345         /* Make sure we left the space for fd mappings */
346         g_assert (handle_idx >= _wapi_fd_reserve);
347         
348         handle = GUINT_TO_POINTER (handle_idx);
349
350 #ifdef DEBUG
351         g_message ("%s: Allocated new handle %p", __func__, handle);
352 #endif
353         
354         if (_WAPI_SHARED_HANDLE(type)) {
355                 /* Add the shared section too */
356                 guint32 offset, ref;
357                 
358                 offset = _wapi_handle_new_shared (type, handle_specific);
359                 if (offset == 0) {
360                         _wapi_handle_collect ();
361                         offset = _wapi_handle_new_shared (type,
362                                                           handle_specific);
363                         /* FIXME: grow the arrays */
364                         g_assert (offset != 0);
365                 }
366                 
367                 ref = _wapi_handle_new_shared_offset (offset);
368                 if (ref == 0) {
369                         _wapi_handle_collect ();
370                         ref = _wapi_handle_new_shared_offset (offset);
371                         /* FIXME: grow the arrays */
372                         g_assert (ref != 0);
373                 }
374                 
375                 _wapi_private_handles[handle_idx].u.shared.offset = ref;
376 #ifdef DEBUG
377                 g_message ("%s: New shared handle at offset 0x%x", __func__,
378                            ref);
379 #endif
380         }
381         
382         return(handle);
383 }
384
385 gpointer _wapi_handle_new_for_existing_ns (WapiHandleType type,
386                                            gpointer handle_specific,
387                                            guint32 offset)
388 {
389         static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
390         guint32 handle_idx = 0;
391         gpointer handle;
392         int thr_ret;
393         
394         mono_once (&shared_init_once, shared_init);
395         
396 #ifdef DEBUG
397         g_message ("%s: Creating new handle of type %s", __func__,
398                    _wapi_handle_typename[type]);
399 #endif
400
401         g_assert(!_WAPI_FD_HANDLE(type));
402         g_assert(_WAPI_SHARED_HANDLE(type));
403         g_assert(offset != 0);
404         
405         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
406                               (void *)&scan_mutex);
407         thr_ret = mono_mutex_lock (&scan_mutex);
408         g_assert (thr_ret == 0);
409                 
410         while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
411                 /* Try and expand the array, and have another go */
412                 _wapi_private_handles = g_renew (struct _WapiHandleUnshared,
413                                                  _wapi_private_handles,
414                                                  _wapi_private_handle_count +
415                                                  _WAPI_HANDLE_INITIAL_COUNT);
416                 memset (_wapi_private_handles +
417                         (_wapi_private_handle_count *
418                          sizeof(struct _WapiHandleUnshared)), '\0',
419                         (_WAPI_HANDLE_INITIAL_COUNT *
420                          sizeof(struct _WapiHandleUnshared)));
421                 
422                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
423         }
424                 
425         thr_ret = mono_mutex_unlock (&scan_mutex);
426         g_assert (thr_ret == 0);
427         pthread_cleanup_pop (0);
428                 
429         /* Make sure we left the space for fd mappings */
430         g_assert (handle_idx >= _wapi_fd_reserve);
431         
432         handle = GUINT_TO_POINTER (handle_idx);
433                 
434         _wapi_private_handles[handle_idx].u.shared.offset = offset;
435
436 #ifdef DEBUG
437         g_message ("%s: Allocated new handle %p referencing 0x%x", __func__,
438                    handle, offset);
439 #endif
440
441         return(handle);
442 }
443
444 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
445                               gpointer handle_specific)
446 {
447         struct _WapiHandleUnshared *handle;
448         
449         mono_once (&shared_init_once, shared_init);
450         
451 #ifdef DEBUG
452         g_message ("%s: Creating new handle of type %s", __func__,
453                    _wapi_handle_typename[type]);
454 #endif
455         
456         g_assert(_WAPI_FD_HANDLE(type));
457         g_assert(!_WAPI_SHARED_HANDLE(type));
458         
459         if (fd >= _wapi_fd_reserve) {
460 #ifdef DEBUG
461                 g_message ("%s: fd %d is too big", __func__, fd);
462 #endif
463
464                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
465         }
466
467         handle = &_wapi_private_handles[fd];
468         
469         if (handle->type != WAPI_HANDLE_UNUSED) {
470 #ifdef DEBUG
471                 g_message ("%s: fd %d is already in use!", __func__, fd);
472 #endif
473                 /* FIXME: clean up this handle?  We can't do anything
474                  * with the fd, cos thats the new one
475                  */
476         }
477
478 #ifdef DEBUG
479         g_message ("%s: Assigning new fd handle %d", __func__, fd);
480 #endif
481
482         _wapi_handle_init (handle, type, handle_specific);
483
484         return(GUINT_TO_POINTER(fd));
485 }
486
487 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
488                               gpointer *handle_specific)
489 {
490         struct _WapiHandleUnshared *handle_data;
491         guint32 handle_idx = GPOINTER_TO_UINT(handle);
492
493         handle_data = &_wapi_private_handles[handle_idx];
494         
495         if (handle_data->type != type) {
496                 return(FALSE);
497         }
498
499         if (handle_specific == NULL) {
500                 return(FALSE);
501         }
502         
503         if (_WAPI_SHARED_HANDLE(type)) {
504                 struct _WapiHandle_shared_ref *ref;
505                 struct _WapiHandleShared *shared_handle_data;
506                 struct _WapiHandleSharedMetadata *shared_meta;
507                 guint32 offset;
508                 
509                 do {
510                         ref = &handle_data->u.shared;
511                         shared_meta = &_wapi_shared_layout->metadata[ref->offset];
512                         offset = shared_meta->offset;
513                         shared_handle_data = &_wapi_shared_layout->handles[offset];
514                 
515                         g_assert(shared_handle_data->type == type);
516
517                         *handle_specific = &shared_handle_data->u;
518                 } while (offset != shared_meta->offset);
519         } else {
520                 *handle_specific = &handle_data->u;
521         }
522         
523         return(TRUE);
524 }
525
526 gboolean _wapi_copy_handle (gpointer handle, WapiHandleType type,
527                             struct _WapiHandleShared *handle_specific)
528 {
529         struct _WapiHandleUnshared *handle_data;
530         guint32 handle_idx = GPOINTER_TO_UINT(handle);
531         struct _WapiHandle_shared_ref *ref;
532         struct _WapiHandleShared *shared_handle_data;
533         struct _WapiHandleSharedMetadata *shared_meta;
534         guint32 offset;
535         
536         g_assert(_WAPI_SHARED_HANDLE(type));
537
538 #ifdef DEBUG
539         g_message ("%s: copying handle %p type %s", __func__, handle,
540                    _wapi_handle_typename[type]);
541 #endif
542
543         handle_data = &_wapi_private_handles[handle_idx];
544         
545         if(handle_data->type != type) {
546 #ifdef DEBUG
547                 g_message ("%s: incorrect type, %p has type %s", __func__,
548                            handle, _wapi_handle_typename[handle_data->type]);
549 #endif
550
551                 return(FALSE);
552         }
553
554         if(handle_specific == NULL) {
555 #ifdef DEBUG
556                 g_message ("%s: Nowhere to store data", __func__);
557 #endif
558
559                 return(FALSE);
560         }
561         
562         do {
563                 ref = &handle_data->u.shared;
564                 shared_meta = &_wapi_shared_layout->metadata[ref->offset];
565                 offset = shared_meta->offset;
566                 shared_handle_data = &_wapi_shared_layout->handles[offset];
567                 
568                 g_assert(shared_handle_data->type == type);
569                 
570                 memcpy(handle_specific, shared_handle_data,
571                        sizeof(struct _WapiHandleShared));
572         } while (offset != shared_meta->offset);
573         
574 #ifdef DEBUG
575         g_message ("%s: OK", __func__);
576 #endif
577
578         return(TRUE);
579 }
580
581 void _wapi_replace_handle (gpointer handle, WapiHandleType type,
582                            struct _WapiHandleShared *handle_specific)
583 {
584         struct _WapiHandleShared *shared_handle_data;
585         struct _WapiHandleSharedMetadata *shared_meta;
586         guint32 handle_idx = GPOINTER_TO_UINT(handle);
587         guint32 old_off, new_off, ref;
588         
589 #ifdef DEBUG
590         g_message ("%s: Replacing handle %p of type %s", __func__, handle,
591                    _wapi_handle_typename[type]);
592 #endif
593
594         g_assert(_WAPI_SHARED_HANDLE(type));
595         g_assert(_wapi_private_handles[handle_idx].type == type);
596         
597         ref = _wapi_private_handles[handle_idx].u.shared.offset;
598         shared_meta = &_wapi_shared_layout->metadata[ref];
599         
600         do {
601                 old_off = shared_meta->offset;
602                 new_off = _wapi_handle_new_shared (type, handle_specific);
603                 if (new_off == 0) {
604                         _wapi_handle_collect ();
605                         new_off = _wapi_handle_new_shared (type, 
606                                                            handle_specific);
607                         /* FIXME: grow the arrays */
608                         g_assert (new_off != 0);
609                 }
610                 
611                 shared_handle_data = &_wapi_shared_layout->handles[new_off];
612
613                 memcpy (shared_handle_data, handle_specific,
614                         sizeof(struct _WapiHandleShared));
615
616                 /* An entry can't become fresh again (its going to be
617                  * collected eventually), so no need for atomic ops
618                  * here.
619                  */
620                 _wapi_shared_layout->handles[old_off].stale = TRUE;
621         } while(InterlockedCompareExchange (&shared_meta->offset, new_off,
622                                             old_off) != old_off);
623
624 #ifdef DEBUG
625         g_message ("%s: handle at 0x%x is now found at 0x%x", __func__, ref,
626                    new_off);
627 #endif
628 }
629
630 gboolean _wapi_try_replace_handle (gpointer handle, WapiHandleType type,
631                                    struct _WapiHandleShared *handle_specific)
632 {
633         struct _WapiHandleShared *shared_handle_data;
634         struct _WapiHandleSharedMetadata *shared_meta;
635         guint32 handle_idx = GPOINTER_TO_UINT(handle);
636         guint32 old_off, new_off, ref;
637         gboolean ret;
638         
639 #ifdef DEBUG
640         g_message ("%s: Trying to replace handle %p of type %s", __func__,
641                    handle, _wapi_handle_typename[type]);
642 #endif
643
644         g_assert(_WAPI_SHARED_HANDLE(type));
645         g_assert(_wapi_private_handles[handle_idx].type == type);
646         
647         ref = _wapi_private_handles[handle_idx].u.shared.offset;
648         shared_meta = &_wapi_shared_layout->metadata[ref];
649         
650         old_off = shared_meta->offset;
651         new_off = _wapi_handle_new_shared (type, handle_specific);
652
653         if (new_off == 0) {
654                 _wapi_handle_collect ();
655                 new_off = _wapi_handle_new_shared (type, handle_specific);
656         
657                 /* FIXME: grow the arrays */
658                 g_assert (new_off != 0);
659         }
660         
661         shared_handle_data = &_wapi_shared_layout->handles[new_off];
662
663 #ifdef DEBUG
664         g_message ("%s: Old offset: 0x%x, trying to move to 0x%x", __func__,
665                    old_off, new_off);
666 #endif
667
668         memcpy (shared_handle_data, handle_specific,
669                 sizeof(struct _WapiHandleShared));
670         
671         ret = (InterlockedCompareExchange (&shared_meta->offset, new_off,
672                                            old_off) == old_off);
673
674         if (ret) {
675                 /* An entry can't become fresh again (its going to be
676                  * collected eventually), so no need for atomic ops
677                  * here.
678                  */
679                 _wapi_shared_layout->handles[old_off].stale = TRUE;
680         }
681
682 #ifdef DEBUG
683         if (ret) {
684                 g_message ("%s: handle at 0x%x is now found at 0x%x", __func__,
685                            ref, new_off);
686         } else {
687                 g_message ("%s: handle at 0x%x already updated", __func__,
688                            ref);
689         }
690 #endif
691
692         return(ret);
693 }
694
695 /* This will only find shared handles that have already been opened by
696  * this process.  To look up shared handles by name, use
697  * _wapi_search_handle_namespace
698  */
699 gpointer _wapi_search_handle (WapiHandleType type,
700                               gboolean (*check)(gpointer test, gpointer user),
701                               gpointer user_data,
702                               gpointer *handle_specific)
703 {
704         struct _WapiHandleUnshared *handle_data = NULL;
705         gpointer ret = NULL;
706         guint32 i;
707
708         /* Unsafe, because we don't want the handle to vanish while
709          * we're checking it
710          */
711         _WAPI_HANDLE_COLLECTION_UNSAFE;
712
713         for(i = 0; i < _wapi_private_handle_count; i++) {
714                 handle_data = &_wapi_private_handles[i];
715                 
716                 if(handle_data->type == type) {
717                         ret = GUINT_TO_POINTER (i);
718                         if(check (ret, user_data) == TRUE) {
719                                 break;
720                         }
721                 }
722         }
723
724         if(i == _wapi_private_handle_count) {
725                 goto done;
726         }
727         
728         if(handle_specific != NULL) {
729                 if (_WAPI_SHARED_HANDLE(type)) {
730                         struct _WapiHandle_shared_ref *ref ;
731                         struct _WapiHandleShared *shared_handle_data;
732                         struct _WapiHandleSharedMetadata *shared_meta;
733                         guint32 offset, now;
734                         
735                         do {
736                                 ref = &handle_data->u.shared;
737                                 shared_meta = &_wapi_shared_layout->metadata[ref->offset];
738                                 offset = shared_meta->offset;
739                                 shared_handle_data = &_wapi_shared_layout->handles[offset];
740                         
741                                 g_assert(shared_handle_data->type == type);
742                         
743                                 *handle_specific = &shared_handle_data->u;
744                         } while (offset != shared_meta->offset);
745
746                         /* Make sure this handle doesn't vanish in the
747                          * next collection
748                          */
749                         now = (guint32)(time (NULL) & 0xFFFFFFFF);
750                         InterlockedExchange (&shared_meta->timestamp, now);
751                 } else {
752                         *handle_specific = &handle_data->u;
753                 }
754         }
755
756 done:
757         _WAPI_HANDLE_COLLECTION_SAFE;
758         
759         return(ret);
760 }
761
762 /* This signature makes it easier to use in pthread cleanup handlers */
763 int _wapi_namespace_timestamp_release (gpointer nowptr)
764 {
765         guint32 now = GPOINTER_TO_UINT(nowptr);
766         
767         return (_wapi_timestamp_release (&_wapi_shared_layout->namespace_check,
768                                          now));
769 }
770
771 int _wapi_namespace_timestamp (guint32 now)
772 {
773         int ret;
774         
775         do {
776                 ret = _wapi_timestamp_exclusion (&_wapi_shared_layout->namespace_check, now);
777                 /* sleep for a bit */
778                 if (ret == EBUSY) {
779                         _wapi_handle_spin (100);
780                 }
781         } while (ret == EBUSY);
782         
783         return(ret);
784 }
785
786 /* Returns the offset of the metadata array, or -1 on error, or 0 for
787  * not found (0 is not a valid offset)
788  */
789 gint32 _wapi_search_handle_namespace (WapiHandleType type,
790                                       gchar *utf8_name)
791 {
792         struct _WapiHandleShared *shared_handle_data;
793         struct _WapiHandleSharedMetadata *shared_meta;
794         guint32 i;
795         gint32 ret = 0;
796         
797         g_assert(_WAPI_SHARED_HANDLE(type));
798         g_assert(_wapi_shared_layout->namespace_check != 0);
799         
800 #ifdef DEBUG
801         g_message ("%s: Lookup for handle named [%s] type %s", __func__,
802                    utf8_name, _wapi_handle_typename[type]);
803 #endif
804
805         _WAPI_HANDLE_COLLECTION_UNSAFE;
806         
807         for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
808                 WapiSharedNamespace *sharedns;
809                 
810                 shared_meta = &_wapi_shared_layout->metadata[i];
811                 shared_handle_data = &_wapi_shared_layout->handles[shared_meta->offset];
812
813                 /* Check mutex, event, semaphore, timer, job and file-mapping
814                  * object names.  So far only mutex is implemented.
815                  */
816                 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
817                         continue;
818                 }
819
820 #ifdef DEBUG
821                 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
822 #endif
823
824                 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
825                         
826 #ifdef DEBUG
827                 g_message ("%s: name is [%s]", __func__, sharedns->name);
828 #endif
829
830                 if (strcmp (sharedns->name, utf8_name) == 0) {
831                         if (shared_handle_data->type != type) {
832                                 /* Its the wrong type, so fail now */
833 #ifdef DEBUG
834                                 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
835 #endif
836                                 ret = -1;
837                                 goto done;
838                         } else {
839 #ifdef DEBUG
840                                 g_message ("%s: handle 0x%x matches name and type", __func__, i);
841 #endif
842                                 ret = i;
843                                 goto done;
844                         }
845                 }
846         }
847
848 done:
849         _WAPI_HANDLE_COLLECTION_SAFE;
850         
851         return(ret);
852 }
853
854 void _wapi_handle_ref (gpointer handle)
855 {
856         guint32 idx = GPOINTER_TO_UINT(handle);
857         
858         InterlockedIncrement (&_wapi_private_handles[idx].ref);
859         
860 #ifdef DEBUG_REFS
861         g_message ("%s: handle %p ref now %d", __func__, handle,
862                    _wapi_private_handles[idx].ref);
863 #endif
864 }
865
866 /* The handle must not be locked on entry to this function */
867 void _wapi_handle_unref (gpointer handle)
868 {
869         guint32 idx = GPOINTER_TO_UINT(handle);
870         gboolean destroy = FALSE;
871         int thr_ret;
872
873         /* Possible race condition here if another thread refs the
874          * handle between here and setting the type to UNUSED.  I
875          * could lock a mutex, but I'm not sure that allowing a handle
876          * reference to reach 0 isn't an application bug anyway.
877          */
878         destroy = (InterlockedDecrement (&_wapi_private_handles[idx].ref) ==0);
879         
880 #ifdef DEBUG_REFS
881         g_message ("%s: handle %p ref now %d (destroy %s)", __func__, handle,
882                    _wapi_private_handles[idx].ref, destroy?"TRUE":"FALSE");
883 #endif
884         
885         if(destroy==TRUE) {
886 #ifdef DEBUG
887                 g_message ("%s: Destroying handle %p", __func__, handle);
888 #endif
889                 
890                 _wapi_handle_ops_close (handle);
891
892                 memset (&_wapi_private_handles[idx].u, '\0',
893                         sizeof(_wapi_private_handles[idx].u));
894
895                 _wapi_private_handles[idx].type = WAPI_HANDLE_UNUSED;
896                 
897                 /* Destroy the mutex and cond var.  We hope nobody
898                  * tried to grab them between the handle unlock and
899                  * now, but pthreads doesn't have a
900                  * "unlock_and_destroy" atomic function.
901                  */
902                 thr_ret = mono_mutex_destroy (&_wapi_private_handles[idx].signal_mutex);
903                 g_assert (thr_ret == 0);
904                         
905                 thr_ret = pthread_cond_destroy (&_wapi_private_handles[idx].signal_cond);
906                 g_assert (thr_ret == 0);
907
908                 /* The garbage collector will take care of shared data
909                  * if this is a shared handle
910                  */
911         }
912 }
913
914 void _wapi_handle_register_capabilities (WapiHandleType type,
915                                          WapiHandleCapability caps)
916 {
917         handle_caps[type] = caps;
918 }
919
920 gboolean _wapi_handle_test_capabilities (gpointer handle,
921                                          WapiHandleCapability caps)
922 {
923         guint32 idx = GPOINTER_TO_UINT(handle);
924         WapiHandleType type;
925
926         type = _wapi_private_handles[idx].type;
927
928 #ifdef DEBUG
929         g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
930                    handle_caps[type], caps, handle_caps[type] & caps);
931 #endif
932         
933         return((handle_caps[type] & caps) != 0);
934 }
935
936 void _wapi_handle_ops_close (gpointer handle)
937 {
938         guint32 idx = GPOINTER_TO_UINT(handle);
939         WapiHandleType type;
940
941         type = _wapi_private_handles[idx].type;
942
943         if (handle_ops[type] != NULL &&
944             handle_ops[type]->close != NULL) {
945                 handle_ops[type]->close (handle);
946         }
947 }
948
949 void _wapi_handle_ops_signal (gpointer handle)
950 {
951         guint32 idx = GPOINTER_TO_UINT(handle);
952         WapiHandleType type;
953
954         type = _wapi_private_handles[idx].type;
955
956         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
957                 handle_ops[type]->signal (handle);
958         }
959 }
960
961 gboolean _wapi_handle_ops_own (gpointer handle)
962 {
963         guint32 idx = GPOINTER_TO_UINT(handle);
964         WapiHandleType type;
965         
966         type = _wapi_private_handles[idx].type;
967
968         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
969                 return(handle_ops[type]->own_handle (handle));
970         } else {
971                 return(FALSE);
972         }
973 }
974
975 gboolean _wapi_handle_ops_isowned (gpointer handle)
976 {
977         guint32 idx = GPOINTER_TO_UINT(handle);
978         WapiHandleType type;
979
980         type = _wapi_private_handles[idx].type;
981
982         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
983                 return(handle_ops[type]->is_owned (handle));
984         } else {
985                 return(FALSE);
986         }
987 }
988
989 /**
990  * CloseHandle:
991  * @handle: The handle to release
992  *
993  * Closes and invalidates @handle, releasing any resources it
994  * consumes.  When the last handle to a temporary or non-persistent
995  * object is closed, that object can be deleted.  Closing the same
996  * handle twice is an error.
997  *
998  * Return value: %TRUE on success, %FALSE otherwise.
999  */
1000 gboolean CloseHandle(gpointer handle)
1001 {
1002         _wapi_handle_unref (handle);
1003         
1004         return(TRUE);
1005 }
1006
1007 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1008                                                gpointer *handles,
1009                                                gboolean waitall,
1010                                                guint32 *retcount,
1011                                                guint32 *lowest)
1012 {
1013         guint32 count, i, iter=0;
1014         gboolean ret;
1015         int thr_ret;
1016         WapiHandleType type;
1017         
1018         /* Lock all the handles, with backoff */
1019 again:
1020         for(i=0; i<numhandles; i++) {
1021                 gpointer handle = handles[i];
1022                 guint32 idx = GPOINTER_TO_UINT(handle);
1023                 guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1024
1025 #ifdef DEBUG
1026                 g_message ("%s: attempting to lock %p", __func__, handle);
1027 #endif
1028
1029                 type = _wapi_private_handles[idx].type;
1030
1031                 if (_WAPI_SHARED_HANDLE(type)) {
1032                         /* We don't lock shared handles, but we need
1033                          * to be able to simultaneously check the
1034                          * signal state of all handles in the array
1035                          *
1036                          * We do this by atomically putting the
1037                          * least-significant 32 bits of time(2) into
1038                          * the 'checking' field if it is zero.  If it
1039                          * isn't zero, then it means that either
1040                          * another thread is looking at this handle
1041                          * right now, or someone crashed here.  Assume
1042                          * that if the time value is more than 10
1043                          * seconds old, its a crash and override it.
1044                          * 10 seconds should be enough for anyone...
1045                          *
1046                          * If the time value is within 10 seconds,
1047                          * back off and try again as per the
1048                          * non-shared case.
1049                          */
1050                         thr_ret = _wapi_timestamp_exclusion (&WAPI_SHARED_HANDLE_METADATA(handle).checking, now);
1051                 } else {
1052                         thr_ret = _wapi_handle_trylock_handle (handle);
1053                 }
1054                 
1055                 if (thr_ret != 0) {
1056                         /* Bummer */
1057                         
1058 #ifdef DEBUG
1059                         g_message ("%s: attempt failed for %p: %s", __func__,
1060                                    handle, strerror (thr_ret));
1061 #endif
1062
1063                         while (i--) {
1064                                 handle = handles[i];
1065                                 idx = GPOINTER_TO_UINT(handle);
1066
1067                                 if (_WAPI_SHARED_HANDLE(type)) {
1068                                         /* Reset the checking field */
1069                                         thr_ret = _wapi_timestamp_release (&WAPI_SHARED_HANDLE_METADATA(handle).checking, now);
1070                                 } else{
1071                                         thr_ret = _wapi_handle_unlock_handle (handle);
1072                                 }
1073                                 g_assert (thr_ret == 0);
1074                         }
1075
1076                         /* If iter ever reaches 100 the nanosleep will
1077                          * return EINVAL immediately, but we have a
1078                          * design flaw if that happens.
1079                          */
1080                         iter++;
1081                         if(iter==100) {
1082                                 g_warning ("%s: iteration overflow!",
1083                                            __func__);
1084                                 iter=1;
1085                         }
1086                         
1087 #ifdef DEBUG
1088                         g_message ("%s: Backing off for %d ms", __func__,
1089                                    iter*10);
1090 #endif
1091                         _wapi_handle_spin (10 * iter);
1092                         
1093                         goto again;
1094                 }
1095         }
1096         
1097 #ifdef DEBUG
1098         g_message ("%s: Locked all handles", __func__);
1099 #endif
1100
1101         count=0;
1102         *lowest=numhandles;
1103         
1104         for(i=0; i<numhandles; i++) {
1105                 gpointer handle = handles[i];
1106                 guint32 idx = GPOINTER_TO_UINT(handle);
1107                 
1108                 type = _wapi_private_handles[idx].type;
1109
1110                 _wapi_handle_ref (handle);
1111                 
1112 #ifdef DEBUG
1113                 g_message ("%s: Checking handle %p", __func__, handle);
1114 #endif
1115
1116                 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1117                     (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1118                    (_WAPI_SHARED_HANDLE(type) &&
1119                     WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) ||
1120                    (!_WAPI_SHARED_HANDLE(type) &&
1121                     _wapi_private_handles[idx].signalled == TRUE)) {
1122                         count++;
1123                         
1124 #ifdef DEBUG
1125                         g_message ("%s: Handle %p signalled", __func__,
1126                                    handle);
1127 #endif
1128                         if(*lowest>i) {
1129                                 *lowest=i;
1130                         }
1131                 }
1132         }
1133         
1134 #ifdef DEBUG
1135         g_message ("%s: %d event handles signalled", __func__, count);
1136 #endif
1137
1138         if ((waitall == TRUE && count == numhandles) ||
1139             (waitall == FALSE && count > 0)) {
1140                 ret=TRUE;
1141         } else {
1142                 ret=FALSE;
1143         }
1144         
1145 #ifdef DEBUG
1146         g_message ("%s: Returning %d", __func__, ret);
1147 #endif
1148
1149         *retcount=count;
1150         
1151         return(ret);
1152 }
1153
1154 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1155 {
1156         guint32 i;
1157         int thr_ret;
1158         
1159         for(i=0; i<numhandles; i++) {
1160                 gpointer handle = handles[i];
1161                 guint32 idx = GPOINTER_TO_UINT(handle);
1162                 WapiHandleType type = _wapi_private_handles[idx].type;
1163                 
1164 #ifdef DEBUG
1165                 g_message ("%s: unlocking handle %p", __func__, handle);
1166 #endif
1167
1168                 if (_WAPI_SHARED_HANDLE(type)) {
1169                         WAPI_SHARED_HANDLE_METADATA(handle).checking = 0;
1170                 } else {
1171                         thr_ret = mono_mutex_unlock (&_wapi_private_handles[idx].signal_mutex);
1172                         g_assert (thr_ret == 0);
1173                 }
1174
1175                 _wapi_handle_unref (handle);
1176         }
1177 }
1178
1179 int _wapi_handle_wait_signal (void)
1180 {
1181         return(mono_cond_wait (&_wapi_global_signal_cond,
1182                                &_wapi_global_signal_mutex));
1183 }
1184
1185 int _wapi_handle_timedwait_signal (struct timespec *timeout)
1186 {
1187         return(mono_cond_timedwait (&_wapi_global_signal_cond,
1188                                     &_wapi_global_signal_mutex,
1189                                     timeout));
1190 }
1191
1192 int _wapi_handle_wait_signal_poll_share (void)
1193 {
1194         struct timespec fake_timeout;
1195         guint32 signal_count = _wapi_shared_layout->signal_count;
1196         int ret;
1197         
1198 #ifdef DEBUG
1199         g_message ("%s: poll private and shared handles", __func__);
1200 #endif
1201
1202         while(1) {
1203                 _wapi_calc_timeout (&fake_timeout, 100);
1204         
1205                 ret = mono_cond_timedwait (&_wapi_global_signal_cond,
1206                                            &_wapi_global_signal_mutex,
1207                                            &fake_timeout);
1208         
1209                 /* Check the shared signal counter */
1210                 if (ret == ETIMEDOUT) {
1211                         if (signal_count != _wapi_shared_layout->signal_count) {
1212 #ifdef DEBUG
1213                                 g_message ("%s: A shared handle was signalled",
1214                                            __func__);
1215 #endif
1216
1217                                 return (0);
1218                         }
1219                 } else {
1220                         /* This will be 0 indicating a private handle
1221                          * was signalled, or an error
1222                          */
1223 #ifdef DEBUG
1224                         g_message ("%s: returning: %d", __func__, ret);
1225 #endif
1226
1227                         return (ret);
1228                 }
1229
1230                 /* If timeout and no shared handle was signalled, go
1231                  * round again
1232                  */
1233         }
1234 }
1235
1236 int _wapi_handle_timedwait_signal_poll_share (struct timespec *timeout)
1237 {
1238         struct timespec fake_timeout;
1239         guint32 signal_count = _wapi_shared_layout->signal_count;
1240         int ret;
1241         
1242 #ifdef DEBUG
1243         g_message ("%s: poll private and shared handles", __func__);
1244 #endif
1245         
1246         do {
1247                 _wapi_calc_timeout (&fake_timeout, 100);
1248         
1249                 if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1250                     (fake_timeout.tv_sec == timeout->tv_sec &&
1251                      fake_timeout.tv_nsec > timeout->tv_nsec)) {
1252                         /* Real timeout is less than 100ms time */
1253
1254 #ifdef DEBUG
1255                         g_message ("%s: last few ms", __func__);
1256 #endif
1257
1258                         ret = mono_cond_timedwait (&_wapi_global_signal_cond,
1259                                                    &_wapi_global_signal_mutex,
1260                                                    timeout);
1261                         /* If this times out, it will compare the
1262                          * shared signal counter and then if that
1263                          * hasn't increased will fall out of the
1264                          * do-while loop.
1265                          */
1266                         if (ret != ETIMEDOUT) {
1267                                 /* Either a private handle was
1268                                  * signalled, or an error.
1269                                  */
1270 #ifdef DEBUG
1271                                 g_message ("%s: returning: %d", __func__, ret);
1272 #endif
1273                                 return (ret);
1274                         }
1275                 } else {
1276                         ret = mono_cond_timedwait (&_wapi_global_signal_cond,
1277                                                    &_wapi_global_signal_mutex,
1278                                                    &fake_timeout);
1279
1280                         /* Mask the fake timeout, this will cause
1281                          * another poll if the shared counter hasn't
1282                          * changed
1283                          */
1284                         if (ret == ETIMEDOUT) {
1285                                 ret = 0;
1286                         } else {
1287                                 /* Either a private handle was
1288                                  * signalled, or an error
1289                                  */
1290 #ifdef DEBUG
1291                                 g_message ("%s: returning: %d", __func__, ret);
1292 #endif
1293                                 return (ret);
1294                         }
1295                 }
1296
1297                 /* No private handle was signalled, so check the
1298                  * shared signal counter
1299                  */
1300                 if (signal_count != _wapi_shared_layout->signal_count) {
1301 #ifdef DEBUG
1302                                 g_message ("%s: A shared handle was signalled",
1303                                            __func__);
1304 #endif
1305                         return (0);
1306                 }
1307         } while (ret != ETIMEDOUT);
1308
1309 #ifdef DEBUG
1310         g_message ("%s: returning ETIMEDOUT", __func__);
1311 #endif
1312
1313         return (ret);
1314 }
1315
1316 int _wapi_handle_wait_signal_handle (gpointer handle)
1317 {
1318         guint32 idx = GPOINTER_TO_UINT(handle);
1319         
1320 #ifdef DEBUG
1321         g_message ("%s: waiting for %p", __func__, handle);
1322 #endif
1323         
1324         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1325                 while(1) {
1326                         if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
1327                                 return (0);
1328                         }
1329                         
1330                         _wapi_handle_spin (100);
1331                 }
1332         } else {
1333                 return(mono_cond_wait (&_wapi_private_handles[idx].signal_cond,
1334                                        &_wapi_private_handles[idx].signal_mutex));
1335         }
1336 }
1337
1338 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1339                                           struct timespec *timeout)
1340 {
1341         guint32 idx = GPOINTER_TO_UINT(handle);
1342         
1343 #ifdef DEBUG
1344         g_message ("%s: waiting for %p (type %s)", __func__, handle,
1345                    _wapi_handle_typename[_wapi_handle_type (handle)]);
1346 #endif
1347         
1348         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1349                 struct timespec fake_timeout;
1350
1351                 while (1) {
1352                         if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
1353                                 return (0);
1354                         }
1355                 
1356                         _wapi_calc_timeout (&fake_timeout, 100);
1357                 
1358                         if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1359                             (fake_timeout.tv_sec == timeout->tv_sec &&
1360                              fake_timeout.tv_nsec > timeout->tv_nsec)) {
1361                                 /* FIXME: Real timeout is less than
1362                                  * 100ms time, but is it really worth
1363                                  * calculating to the exact ms?
1364                                  */
1365                                 _wapi_handle_spin (100);
1366                                 
1367                                 if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
1368                                         return (0);
1369                                 } else {
1370                                         return (ETIMEDOUT);
1371                                 }
1372                         } else {
1373                                 _wapi_handle_spin (100);
1374                         }
1375                 }
1376         } else {
1377                 return(mono_cond_timedwait (&_wapi_private_handles[idx].signal_cond, &_wapi_private_handles[idx].signal_mutex, timeout));
1378         }
1379 }
1380
1381 gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
1382                                     gboolean inherit, guint32 flags,
1383                                     gpointer stdin_handle,
1384                                     gpointer stdout_handle,
1385                                     gpointer stderr_handle,
1386                                     gpointer *process_handle,
1387                                     gpointer *thread_handle, guint32 *pid,
1388                                     guint32 *tid)
1389 {
1390 #if 0
1391         WapiHandleRequest fork_proc={0};
1392         WapiHandleResponse fork_proc_resp={0};
1393         int in_fd, out_fd, err_fd;
1394         
1395         if(shared!=TRUE) {
1396                 return(FALSE);
1397         }
1398
1399         fork_proc.type=WapiHandleRequestType_ProcessFork;
1400         fork_proc.u.process_fork.cmd=cmd;
1401         fork_proc.u.process_fork.env=env;
1402         fork_proc.u.process_fork.dir=dir;
1403         fork_proc.u.process_fork.stdin_handle=GPOINTER_TO_UINT (stdin_handle);
1404         fork_proc.u.process_fork.stdout_handle=GPOINTER_TO_UINT (stdout_handle);
1405         fork_proc.u.process_fork.stderr_handle=GPOINTER_TO_UINT (stderr_handle);
1406         fork_proc.u.process_fork.inherit=inherit;
1407         fork_proc.u.process_fork.flags=flags;
1408         
1409         in_fd = GPOINTER_TO_UINT (stdin_handle);
1410         out_fd = GPOINTER_TO_UINT (stdout_handle);
1411         err_fd = GPOINTER_TO_UINT (stderr_handle);
1412
1413         if(in_fd==-1 || out_fd==-1 || err_fd==-1) {
1414                 /* We were given duff handles */
1415                 /* FIXME: error code */
1416                 return(FALSE);
1417         }
1418         
1419         _wapi_daemon_request_response_with_fds (daemon_sock, &fork_proc,
1420                                                 &fork_proc_resp, in_fd,
1421                                                 out_fd, err_fd);
1422         if(fork_proc_resp.type==WapiHandleResponseType_ProcessFork) {
1423                 *process_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.process_handle);
1424                 *thread_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.thread_handle);
1425                 *pid=fork_proc_resp.u.process_fork.pid;
1426                 *tid=fork_proc_resp.u.process_fork.tid;
1427
1428                 /* If there was an internal error, the handles will be
1429                  * 0.  If there was an error forking or execing, the
1430                  * handles will have values, and process_handle's
1431                  * exec_errno will be set, and the handle will be
1432                  * signalled immediately.
1433                  */
1434                 if(*process_handle==0 || *thread_handle==0) {
1435                         return(FALSE);
1436                 } else {
1437                         /* This call returns new handles, so we need to do
1438                          * a little bookkeeping
1439                          */
1440                         if (_wapi_private_data != NULL) {
1441                                 guint32 segment, idx;
1442
1443                                 _wapi_handle_segment (*process_handle,
1444                                                       &segment, &idx);
1445                                 _wapi_handle_ensure_mapped (segment);
1446                                 _wapi_handle_get_private_segment (segment)->handles[idx].type = WAPI_HANDLE_PROCESS;
1447
1448                                 _wapi_handle_segment (*thread_handle,
1449                                                       &segment, &idx);
1450                                 _wapi_handle_ensure_mapped (segment);
1451                                 _wapi_handle_get_private_segment (segment)->handles[idx].type = WAPI_HANDLE_THREAD;
1452                         }
1453
1454                         return(TRUE);
1455                 }
1456         } else {
1457                 g_warning ("%s: bogus daemon response, type %d", __func__,
1458                            fork_proc_resp.type);
1459                 g_assert_not_reached ();
1460         }
1461         
1462         return(FALSE);
1463 #else
1464         return(FALSE);
1465 #endif
1466 }
1467
1468 gboolean
1469 _wapi_handle_process_kill (pid_t process, guint32 signo, gint *errnum)
1470 {
1471 #if 0
1472         WapiHandleRequest killproc = {0};
1473         WapiHandleResponse killprocresp = {0};
1474         gint result;
1475         
1476         if (shared != TRUE) {
1477                 if (errnum) *errnum = EINVAL;
1478                 return FALSE;
1479         }
1480
1481         killproc.type = WapiHandleRequestType_ProcessKill;
1482         killproc.u.process_kill.pid = process;
1483         killproc.u.process_kill.signo = signo;
1484         
1485         _wapi_daemon_request_response (daemon_sock, &killproc, &killprocresp);
1486
1487         if (killprocresp.type != WapiHandleResponseType_ProcessKill) {
1488                 g_warning ("%s: bogus daemon response, type %d", __func__,
1489                            killprocresp.type);
1490                 g_assert_not_reached ();
1491         }
1492
1493         result = killprocresp.u.process_kill.err;
1494         if (result != 0 && errnum != NULL)
1495                 *errnum = (result == FALSE) ? result : 0;
1496         
1497         return (result == 0);
1498 #else
1499         return(FALSE);
1500 #endif
1501 }
1502
1503 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1504                                         guint32 new_sharemode,
1505                                         guint32 new_access,
1506                                         guint32 *old_sharemode,
1507                                         guint32 *old_access,
1508                                         struct _WapiFileShare **share_info)
1509 {
1510         struct _WapiFileShare *file_share;
1511         guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1512         int thr_ret, i, first_unused = -1;
1513         gboolean exists = FALSE;
1514         
1515         /* Marking this as COLLECTION_UNSAFE prevents entries from
1516          * expiring under us as we search
1517          */
1518         _WAPI_HANDLE_COLLECTION_UNSAFE;
1519         
1520         /* Prevent new entries racing with us */
1521         do {
1522                 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1523
1524                 thr_ret = _wapi_timestamp_exclusion (&_wapi_fileshare_layout->share_check, now);
1525                 if (thr_ret == EBUSY) {
1526                         _wapi_handle_spin (100);
1527                 }
1528         } while (thr_ret == EBUSY);
1529         g_assert (thr_ret == 0);
1530         
1531         /* If a linear scan gets too slow we'll have to fit a hash
1532          * table onto the shared mem backing store
1533          */
1534         *share_info = NULL;
1535         for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1536                 file_share = &_wapi_fileshare_layout->share_info[i];
1537
1538                 /* Make a note of an unused slot, in case we need to
1539                  * store share info
1540                  */
1541                 if (first_unused == -1 && file_share->handle_refs == 0) {
1542                         first_unused = i;
1543                         continue;
1544                 }
1545                 
1546                 if (file_share->handle_refs == 0) {
1547                         continue;
1548                 }
1549                 
1550                 if (file_share->device == device &&
1551                     file_share->inode == inode) {
1552                         *old_sharemode = file_share->sharemode;
1553                         *old_access = file_share->access;
1554                         *share_info = file_share;
1555                         
1556                         /* Increment the reference count while we
1557                          * still have sole access to the shared area.
1558                          * This makes the increment atomic wrt
1559                          * collections
1560                          */
1561                         InterlockedIncrement (&file_share->handle_refs);
1562                         
1563                         exists = TRUE;
1564                         break;
1565                 }
1566         }
1567         
1568         if (!exists) {
1569                 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1570                         /* No more space */
1571                 } else {
1572                         if (first_unused == -1) {
1573                                 file_share = &_wapi_fileshare_layout->share_info[++i];
1574                                 _wapi_fileshare_layout->hwm = i;
1575                         } else {
1576                                 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1577                         }
1578                         
1579                         file_share->device = device;
1580                         file_share->inode = inode;
1581                         file_share->sharemode = new_sharemode;
1582                         file_share->access = new_access;
1583                         file_share->handle_refs = 1;
1584                         *share_info = file_share;
1585                 }
1586         }
1587
1588         if (*share_info != NULL) {
1589                 InterlockedExchange (&(*share_info)->timestamp, now);
1590         }
1591         
1592         thr_ret = _wapi_timestamp_release (&_wapi_fileshare_layout->share_check, now);
1593
1594         _WAPI_HANDLE_COLLECTION_SAFE;
1595
1596         return(exists);
1597 }
1598
1599 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1600  * question.  If there are none, reset the share info.
1601  *
1602  * This implementation is Linux-specific; legacy systems will have to
1603  * implement their own ways of finding out if a particular file is
1604  * open by a process.
1605  */
1606 void _wapi_handle_check_share (struct _WapiFileShare *share_info)
1607 {
1608         DIR *proc_dir;
1609         struct dirent *proc_entry;
1610         gboolean found = FALSE;
1611         pid_t self = getpid();
1612         int pid;
1613         guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1614         int thr_ret;
1615         
1616         proc_dir = opendir ("/proc");
1617         if (proc_dir == NULL) {
1618                 return;
1619         }
1620         
1621         /* Marking this as COLLECTION_UNSAFE prevents entries from
1622          * expiring under us if we remove this one
1623          */
1624         _WAPI_HANDLE_COLLECTION_UNSAFE;
1625         
1626         /* Prevent new entries racing with us */
1627         do {
1628                 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1629
1630                 thr_ret = _wapi_timestamp_exclusion (&_wapi_fileshare_layout->share_check, now);
1631                 if (thr_ret == EBUSY) {
1632                         _wapi_handle_spin (100);
1633                 }
1634         } while (thr_ret == EBUSY);
1635         g_assert (thr_ret == 0);
1636
1637         while ((proc_entry = readdir (proc_dir)) != NULL) {
1638                 /* We only care about numerically-named directories */
1639                 pid = atoi (proc_entry->d_name);
1640                 if (pid != 0 && pid != self) {
1641                         /* Look in /proc/<pid>/fd/ but ignore
1642                          * ourselves, as we have the file open too
1643                          */
1644                         DIR *fd_dir;
1645                         struct dirent *fd_entry;
1646                         char subdir[_POSIX_PATH_MAX];
1647                         
1648                         g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
1649                                     pid);
1650                         
1651                         fd_dir = opendir (subdir);
1652                         if (fd_dir == NULL) {
1653                                 continue;
1654                         }
1655                         
1656                         while ((fd_entry = readdir (fd_dir)) != NULL) {
1657                                 char path[_POSIX_PATH_MAX];
1658                                 struct stat link_stat;
1659                                 
1660                                 if (!strcmp (fd_entry->d_name, ".") ||
1661                                     !strcmp (fd_entry->d_name, "..")) {
1662                                         continue;
1663                                 }
1664
1665                                 g_snprintf (path, _POSIX_PATH_MAX,
1666                                             "/proc/%d/fd/%s", pid,
1667                                             fd_entry->d_name);
1668                                 
1669                                 stat (path, &link_stat);
1670                                 if (link_stat.st_dev == share_info->device &&
1671                                     link_stat.st_ino == share_info->inode) {
1672 #ifdef DEBUG
1673                                         g_message ("%s:  Found it at %s",
1674                                                    __func__, path);
1675 #endif
1676
1677                                         found = TRUE;
1678                                 }
1679                         }
1680                         
1681                         closedir (fd_dir);
1682                 }
1683         }
1684         
1685         closedir (proc_dir);
1686
1687         if (found == FALSE) {
1688                 /* Blank out this entry, as it is stale */
1689 #ifdef DEBUG
1690                 g_message ("%s: Didn't find it, destroying entry", __func__);
1691 #endif
1692
1693                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1694         }
1695
1696         thr_ret = _wapi_timestamp_release (&_wapi_fileshare_layout->share_check, now);
1697
1698         _WAPI_HANDLE_COLLECTION_SAFE;
1699 }
1700
1701 void _wapi_handle_dump (void)
1702 {
1703         struct _WapiHandleUnshared *handle_data;
1704         guint32 i;
1705
1706         for (i = 0; i < _wapi_private_handle_count; i++) {
1707                 handle_data = &_wapi_private_handles[i];
1708
1709                 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1710                         continue;
1711                 }
1712                 
1713                 g_print ("%3x [%7s] %s %d ", i,
1714                          _wapi_handle_typename[handle_data->type],
1715                          handle_data->signalled?"Sg":"Un", handle_data->ref);
1716                 handle_details[handle_data->type](&handle_data->u);
1717                 g_print ("\n");
1718         }
1719 }
1720
1721 static void _wapi_shared_details (gpointer handle_info)
1722 {
1723         struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1724         
1725         g_print ("offset: 0x%x", shared->offset);
1726 }
1727
1728 void _wapi_handle_update_refs (void)
1729 {
1730         guint32 i;
1731         
1732         _WAPI_HANDLE_COLLECTION_UNSAFE;
1733
1734         for (i = 0; i < _wapi_private_handle_count; i++) {
1735                 struct _WapiHandleUnshared *handle = &_wapi_private_handles[i];
1736                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1737
1738                 if (_WAPI_SHARED_HANDLE(handle->type)) {
1739                         struct _WapiHandleSharedMetadata *shared_meta;
1740                         
1741 #ifdef DEBUG
1742                         g_message ("%s: (%d) handle 0x%x is SHARED", __func__,
1743                                    getpid (), i);
1744 #endif
1745
1746                         shared_meta = &_wapi_shared_layout->metadata[handle->u.shared.offset];
1747
1748 #ifdef DEBUG
1749                         g_message ("%s: (%d) Updating timstamp of handle 0x%x",
1750                                    __func__, getpid(),
1751                                    handle->u.shared.offset);
1752 #endif
1753
1754                         InterlockedExchange (&shared_meta->timestamp, now);
1755                 } else if (handle->type == WAPI_HANDLE_FILE) {
1756                         struct _WapiHandle_file *file_handle = &handle->u.file;
1757                         
1758 #ifdef DEBUG
1759                         g_message ("%s: (%d) handle 0x%x is FILE", __func__,
1760                                    getpid (), i);
1761 #endif
1762                         
1763                         g_assert (file_handle->share_info != NULL);
1764
1765 #ifdef DEBUG
1766                         g_message ("%s: (%d) Inc refs on fileshare 0x%x",
1767                                    __func__, getpid(),
1768                                    (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
1769 #endif
1770
1771                         InterlockedExchange (&file_handle->share_info->timestamp, now);
1772                 }
1773         }
1774         
1775         _WAPI_HANDLE_COLLECTION_SAFE;
1776 }