2004-01-29 Zoltan Varga <vargaz@freemail.hu>
[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
21 #include <mono/os/gc_wrapper.h>
22
23 #include <mono/io-layer/wapi.h>
24 #include <mono/io-layer/wapi-private.h>
25 #include <mono/io-layer/handles-private.h>
26 #include <mono/io-layer/mono-mutex.h>
27 #include <mono/io-layer/shared.h>
28 #include <mono/io-layer/misc-private.h>
29 #include <mono/io-layer/daemon-messages.h>
30
31 #undef DEBUG
32 #undef HEAVY_DEBUG /* This will print handle counts on every handle created */
33
34 /* Shared threads don't seem to work yet */
35 #undef _POSIX_THREAD_PROCESS_SHARED
36
37 /*
38  * This flag _MUST_ remain set to FALSE in the daemon process.  When
39  * we exec()d a standalone daemon, that happened because shared_init()
40  * didnt get called in the daemon process.  Now we just fork() without
41  * exec(), we need to ensure that the fork() happens when shared is
42  * still FALSE.
43  *
44  * This is further complicated by the second attempt to start the
45  * daemon if the connect() fails.
46  */
47 static gboolean shared=FALSE;
48
49 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
50 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
51         NULL,
52         &_wapi_file_ops,
53         &_wapi_console_ops,
54         &_wapi_thread_ops,
55         &_wapi_sem_ops,
56         &_wapi_mutex_ops,
57         &_wapi_event_ops,
58         &_wapi_socket_ops,
59         &_wapi_find_ops,
60         &_wapi_process_ops,
61         &_wapi_pipe_ops,
62 };
63
64 static int daemon_sock;
65
66 static pthread_mutexattr_t mutex_shared_attr;
67 static pthread_condattr_t cond_shared_attr;
68
69 struct _WapiHandleShared_list **_wapi_shared_data=NULL;
70 struct _WapiHandleScratch *_wapi_shared_scratch=NULL;
71 struct _WapiHandlePrivate_list **_wapi_private_data=NULL;
72 pthread_mutex_t _wapi_shared_mutex=PTHREAD_MUTEX_INITIALIZER;
73
74 /* This holds the length of the _wapi_shared_data and
75  * _wapi_private_data arrays, so we know if a segment is off the end
76  * of the array, requiring a realloc
77  */
78 guint32 _wapi_shm_mapped_segments;
79
80 static void shared_init (void)
81 {
82         struct sockaddr_un shared_socket_address;
83         gboolean tried_once=FALSE;
84         int ret;
85
86         _wapi_shared_data=g_new0 (struct _WapiHandleShared_list *, 1);
87         _wapi_private_data=g_new0 (struct _WapiHandlePrivate_list *, 1);
88         
89 attach_again:
90
91 #ifndef DISABLE_SHARED_HANDLES
92         if(getenv ("MONO_DISABLE_SHM"))
93 #endif
94         {
95                 shared=FALSE;
96 #ifndef DISABLE_SHARED_HANDLES
97         } else {
98                 /* Ensure that shared==FALSE while _wapi_shm_attach()
99                  * calls fork()
100                  */
101                 shared=FALSE;
102                 
103                 shared=_wapi_shm_attach (&_wapi_shared_data[0],
104                                          &_wapi_shared_scratch);
105                 if(shared==FALSE) {
106                         g_warning ("Failed to attach shared memory! "
107                                    "Falling back to non-shared handles");
108                 }
109 #endif /* DISABLE_SHARED_HANDLES */
110         }
111         
112
113         if(shared==TRUE) {
114                 daemon_sock=socket (PF_UNIX, SOCK_STREAM, 0);
115                 shared_socket_address.sun_family=AF_UNIX;
116                 memcpy (shared_socket_address.sun_path,
117                         _wapi_shared_data[0]->daemon, MONO_SIZEOF_SUNPATH);
118                 ret=connect (daemon_sock,
119                              (struct sockaddr *)&shared_socket_address,
120                              sizeof(struct sockaddr_un));
121                 if(ret==-1) {
122                         if(tried_once==TRUE) {
123                                 g_warning (G_GNUC_PRETTY_FUNCTION
124                                            ": connect to daemon failed: %s",
125                                            g_strerror (errno));
126                                 /* Fall back to private handles */
127                                 shared=FALSE;
128                         } else {
129                                 /* It's possible that the daemon
130                                  * crashed without destroying the
131                                  * shared memory segment (thus fooling
132                                  * subsequent processes into thinking
133                                  * the daemon is still active).
134                                  * 
135                                  * Destroy the shared memory segment
136                                  * and try once more.  This won't
137                                  * break running apps, but no new apps
138                                  * will be able to see the current
139                                  * shared memory segment.
140                                  */
141                                 tried_once=TRUE;
142                                 _wapi_shm_destroy ();
143                                 
144                                 goto attach_again;
145                         }
146                 }
147         }
148
149         if(shared==FALSE) {
150 #ifdef DEBUG
151                 g_message (G_GNUC_PRETTY_FUNCTION
152                            ": Using process-private handles");
153 #endif
154                 _wapi_shared_data[0]=g_new0 (struct _WapiHandleShared_list, 1);
155                 _wapi_shared_data[0]->num_segments=1;
156
157                 _wapi_shared_scratch=g_new0 (struct _WapiHandleScratch, 1);
158         }
159         _wapi_private_data[0]=g_new0 (struct _WapiHandlePrivate_list, 1);
160         _wapi_shm_mapped_segments=1;
161
162         pthread_mutexattr_init (&mutex_shared_attr);
163         pthread_condattr_init (&cond_shared_attr);
164
165 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
166         pthread_mutexattr_setpshared (&mutex_shared_attr,
167                                       PTHREAD_PROCESS_SHARED);
168         pthread_condattr_setpshared (&cond_shared_attr,
169                                      PTHREAD_PROCESS_SHARED);
170 #else
171         pthread_cond_init(&_wapi_private_data[0]->signal_cond, NULL);
172         mono_mutex_init(&_wapi_private_data[0]->signal_mutex, NULL);
173 #endif
174 }
175
176 #ifdef HEAVY_DEBUG
177 static void
178 print_handle_count (gint mask)
179 {
180         gint *count, num_handles;
181         gint i;
182         static const gchar *names [] = {"WAPI_HANDLE_UNUSED",
183                                   "WAPI_HANDLE_FILE",
184                                   "WAPI_HANDLE_CONSOLE",
185                                   "WAPI_HANDLE_THREAD",
186                                   "WAPI_HANDLE_SEM",
187                                   "WAPI_HANDLE_MUTEX",
188                                   "WAPI_HANDLE_EVENT",
189                                   "WAPI_HANDLE_SOCKET",
190                                   "WAPI_HANDLE_FIND",
191                                   "WAPI_HANDLE_PROCESS",
192                                   "WAPI_HANDLE_PIPE"
193                                 };
194
195
196         num_handles=_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT;
197         count=g_new0 (gint, num_handles);
198
199         for (i = 1; i < num_handles; i++) {
200                 struct _WapiHandleShared *shared;
201                 guint32 segment, idx;
202                 
203                 _wapi_handle_segment (GUINT_TO_POINTER (i), &segment, &idx);
204                 _wapi_handle_ensure_mapped (segment);
205                 
206                 shared = &_wapi_handle_get_shared_segment (segment)->handles[idx];
207                 count [shared->type]++;
208         }
209
210         for (i = 0; i < num_handles; i++)
211                 if ((i & mask) == i) /* Always prints the UNUSED count */
212                         g_print ("%s: %d\n", names [i], count [i]);
213
214         g_free (count);
215 }
216 #endif /* HEAVY_DEBUG */
217
218 /*
219  * _wapi_handle_new_internal:
220  * @type: Init handle to this type
221  *
222  * Search for a free handle and initialize it. Return the handle on
223  * success and 0 on failure.
224  */
225 guint32 _wapi_handle_new_internal (WapiHandleType type)
226 {
227         guint32 segment, idx;
228         guint32 i, j;
229         static guint32 last=1;
230         
231         /* A linear scan should be fast enough.  Start from the last
232          * allocation, assuming that handles are allocated more often
233          * than they're freed. Leave 0 (NULL) as a guard
234          */
235 #ifdef HEAVY_DEBUG
236         print_handle_count (0xFFF);
237 #endif
238 again:
239         _wapi_handle_segment (GUINT_TO_POINTER (last), &segment, &idx);
240         for(i=segment; i<_wapi_handle_get_shared_segment (0)->num_segments;
241             i++) {
242                 if(i!=segment) {
243                         idx=0;
244                 }
245                 
246                 for(j=idx; j<_WAPI_HANDLES_PER_SEGMENT; j++) {
247                         struct _WapiHandleShared *shared;
248                 
249                         /* Make sure we dont try and assign handle 0 */
250                         if (i==0 && j==0) {
251                                 continue;
252                         }
253                         
254                         shared=&_wapi_handle_get_shared_segment (i)->handles[j];
255                 
256                         if(shared->type==WAPI_HANDLE_UNUSED) {
257                                 last=(_wapi_handle_index (i, j)+1) % (_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT);
258                                 shared->type=type;
259                                 shared->signalled=FALSE;
260 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
261                                 mono_mutex_init (&shared->signal_mutex, &mutex_shared_attr);
262                                 pthread_cond_init (&shared->signal_cond, &cond_shared_attr);
263 #else
264                                 pthread_cond_init(&shared->signal_cond, NULL);
265                                 mono_mutex_init(&shared->signal_mutex, NULL);
266 #endif
267                                 
268                                 return(_wapi_handle_index (i, j));
269                         }
270                 }
271         }
272
273         if(last>1) {
274                 /* Try again from the beginning */
275                 last=1;
276                 goto again;
277         }
278
279         /* Will need a new segment.  The caller will sort it out */
280
281         return(0);
282 }
283
284 gpointer _wapi_handle_new (WapiHandleType type)
285 {
286         static mono_once_t shared_init_once = MONO_ONCE_INIT;
287         static pthread_mutex_t scan_mutex=PTHREAD_MUTEX_INITIALIZER;
288         guint32 handle_idx, idx, segment;
289         gpointer handle;
290         WapiHandleRequest new={0};
291         WapiHandleResponse new_resp={0};
292 #if HAVE_BOEHM_GC
293         gboolean tried_collect=FALSE;
294 #endif
295         
296         mono_once (&shared_init_once, shared_init);
297
298 again:
299         if(shared==TRUE) {
300                 new.type=WapiHandleRequestType_New;
301                 new.u.new.type=type;
302         
303                 _wapi_daemon_request_response (daemon_sock, &new, &new_resp);
304         
305                 if (new_resp.type==WapiHandleResponseType_New) {
306                         handle_idx=new_resp.u.new.handle;
307                 } else {
308                         g_warning (G_GNUC_PRETTY_FUNCTION
309                                    ": bogus daemon response, type %d",
310                                    new_resp.type);
311                         g_assert_not_reached ();
312                 }
313         } else {
314                 pthread_mutex_lock (&scan_mutex);
315                 handle_idx=_wapi_handle_new_internal (type);
316                 if(handle_idx==0) {
317                         /* Try and get a new segment, and have another go */
318                         segment=_wapi_handle_get_shared_segment (0)->num_segments;
319                         _wapi_handle_ensure_mapped (segment);
320                         
321                         if(_wapi_handle_get_shared_segment (segment)!=NULL) {
322                                 /* Got a new segment */
323                                 _wapi_handle_get_shared_segment (0)->num_segments++;
324                                 handle_idx=_wapi_handle_new_internal (type);
325                         } else {
326                                 /* Map failed.  Just return 0 meaning
327                                  * "out of handles"
328                                  */
329                         }
330                 }
331                 
332                 _wapi_handle_segment (GUINT_TO_POINTER (handle_idx), &segment, &idx);
333                 _wapi_handle_get_shared_segment (segment)->handles[idx].ref++;
334                 pthread_mutex_unlock (&scan_mutex);
335         }
336                 
337         if(handle_idx==0) {
338                 g_warning (G_GNUC_PRETTY_FUNCTION ": Ran out of handles!");
339
340 #if HAVE_BOEHM_GC
341                 /* See if we can reclaim some handles by forcing a GC
342                  * collection
343                  */
344                 if(tried_collect==FALSE) {
345                         g_warning (G_GNUC_PRETTY_FUNCTION
346                                    ": Seeing if GC collection helps...");
347                         GC_gcollect (); /* FIXME: we should wait for finalizers to be called */
348                         tried_collect=TRUE;
349                         goto again;
350                 } else {
351                         g_warning (G_GNUC_PRETTY_FUNCTION
352                                    ": didn't help, returning error");
353                 }
354 #endif
355         
356                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
357         }
358
359         _wapi_handle_segment (GUINT_TO_POINTER (handle_idx), &segment, &idx);
360         _wapi_handle_ensure_mapped (segment);
361
362         if(_wapi_private_data!=NULL) {
363                 _wapi_handle_get_private_segment (segment)->handles[idx].type=type;
364         }
365         
366 #if !defined(_POSIX_THREAD_PROCESS_SHARED) || _POSIX_THREAD_PROCESS_SHARED == -1
367         mono_mutex_init (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex, &mutex_shared_attr);
368         pthread_cond_init (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond, &cond_shared_attr);
369 #endif
370         handle=GUINT_TO_POINTER (handle_idx);
371
372 #ifdef DEBUG
373         g_message (G_GNUC_PRETTY_FUNCTION ": Allocated new handle %p", handle);
374 #endif
375         
376         return(handle);
377 }
378
379 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
380                               gpointer *shared, gpointer *private)
381 {
382         struct _WapiHandleShared *shared_handle_data;
383         struct _WapiHandlePrivate *private_handle_data;
384         guint32 idx;
385         guint32 segment;
386
387         _wapi_handle_segment (handle, &segment, &idx);
388         _wapi_handle_ensure_mapped (segment);
389         
390         shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
391
392         if(shared!=NULL) {
393                 *shared=&shared_handle_data->u;
394         }
395         
396         if(private!=NULL) {
397                 private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
398
399                 *private=&private_handle_data->u;
400         }
401
402         if(shared_handle_data->type!=type) {
403                 /* If shared type is UNUSED, see if the private type
404                  * matches what we are looking for - this can happen
405                  * when the handle is being destroyed and the
406                  * close_private function is looking up the private
407                  * data
408                  */
409                 if(shared_handle_data->type==WAPI_HANDLE_UNUSED &&
410                    (private!=NULL && private_handle_data->type==type)) {
411                         return(TRUE);
412                 } else {
413                         return(FALSE);
414                 }
415         }
416         
417         return(TRUE);
418 }
419
420 gpointer _wapi_search_handle (WapiHandleType type,
421                               gboolean (*check)(gpointer test, gpointer user),
422                               gpointer user_data,
423                               gpointer *shared, gpointer *private)
424 {
425         struct _WapiHandleShared *shared_handle_data;
426         struct _WapiHandlePrivate *private_handle_data;
427         guint32 i, segment, idx;
428
429         for(i=1; i<_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT; i++) {
430                 struct _WapiHandleShared *shared;
431                 
432                 _wapi_handle_segment (GUINT_TO_POINTER (i), &segment, &idx);
433                 _wapi_handle_ensure_mapped (segment);
434                 
435                 shared=&_wapi_handle_get_shared_segment (segment)->handles[idx];
436                 
437                 if(shared->type==type) {
438                         if(check (GUINT_TO_POINTER (i), user_data)==TRUE) {
439                                 break;
440                         }
441                 }
442         }
443
444         if(i==_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT) {
445                 return(GUINT_TO_POINTER (0));
446         }
447         
448         if(shared!=NULL) {
449                 shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
450
451                 *shared=&shared_handle_data->u;
452         }
453         
454         if(private!=NULL) {
455                 private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
456
457                 *private=&private_handle_data->u;
458         }
459         
460         return(GUINT_TO_POINTER (i));
461 }
462
463 gpointer _wapi_search_handle_namespace (WapiHandleType type,
464                                         gchar *utf8_name, gpointer *shared,
465                                         gpointer *private)
466 {
467         struct _WapiHandleShared *shared_handle_data;
468         struct _WapiHandlePrivate *private_handle_data;
469         guint32 i, segment, idx;
470
471 #ifdef DEBUG
472         g_message (G_GNUC_PRETTY_FUNCTION
473                    ": Lookup for handle named [%s] type %d", utf8_name, type);
474 #endif
475
476         for(i=1; i<_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT; i++) {
477                 struct _WapiHandleShared *shared;
478                 
479                 _wapi_handle_segment (GUINT_TO_POINTER (i), &segment, &idx);
480                 _wapi_handle_ensure_mapped (segment);
481                 
482                 shared=&_wapi_handle_get_shared_segment (segment)->handles[idx];
483                 
484                 /* Check mutex, event, semaphore, timer, job and file-mapping
485                  * object names.  So far only mutex is implemented.
486                  */
487                 if(_WAPI_SHARED_NAMESPACE (shared->type)) {
488                         gchar *lookup_name;
489                         WapiSharedNamespace *sharedns;
490                         
491 #ifdef DEBUG
492                         g_message (G_GNUC_PRETTY_FUNCTION ": found a shared namespace handle at 0x%x (type %d)", i, shared->type);
493 #endif
494
495                         shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
496                         sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
497                         
498                         
499                         if(sharedns->name) {
500                                 lookup_name=_wapi_handle_scratch_lookup (
501                                         sharedns->name);
502                         } else {
503 #ifdef DEBUG
504                                 g_message (G_GNUC_PRETTY_FUNCTION
505                                            ": handle 0x%x is unnamed", i);
506 #endif
507                                 continue;
508                         }
509
510                         if(lookup_name==NULL) {
511 #ifdef DEBUG
512                                 g_message (G_GNUC_PRETTY_FUNCTION
513                                            ": couldn't find handle 0x%x name",
514                                            i);
515 #endif
516                                 continue;
517                         }
518
519 #ifdef DEBUG
520                         g_message (G_GNUC_PRETTY_FUNCTION ": name is [%s]",
521                                    lookup_name);
522 #endif
523
524                         if(strcmp (lookup_name, utf8_name)==0) {
525                                 if(shared->type!=type) {
526                                         /* Its the wrong type, so fail now */
527 #ifdef DEBUG
528                                         g_message (G_GNUC_PRETTY_FUNCTION ": handle 0x%x matches name but is wrong type: %d", i, shared->type);
529 #endif
530                                         return(_WAPI_HANDLE_INVALID);
531                                 } else {
532                                         /* fall through so we can fill
533                                          * in the data
534                                          */
535 #ifdef DEBUG
536                                         g_message (G_GNUC_PRETTY_FUNCTION ": handle 0x%x matches name and type", i);
537 #endif
538                                         break;
539                                 }
540                         }
541                 }
542         }
543
544         if(i==_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT) {
545                 return(GUINT_TO_POINTER (0));
546         }
547         
548         if(shared!=NULL) {
549                 shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
550
551                 *shared=&shared_handle_data->u;
552         }
553         
554         if(private!=NULL) {
555                 private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
556
557                 *private=&private_handle_data->u;
558         }
559         
560         return(GUINT_TO_POINTER (i));
561 }
562
563 void _wapi_handle_ref (gpointer handle)
564 {
565         if(shared==TRUE) {
566                 WapiHandleRequest req={0};
567                 WapiHandleResponse resp={0};
568         
569                 req.type=WapiHandleRequestType_Open;
570                 req.u.open.handle=GPOINTER_TO_UINT (handle);
571         
572                 _wapi_daemon_request_response (daemon_sock, &req, &resp);
573                 if(resp.type!=WapiHandleResponseType_Open) {
574                         g_warning (G_GNUC_PRETTY_FUNCTION
575                                    ": bogus daemon response, type %d",
576                                    resp.type);
577                         g_assert_not_reached ();
578                 }
579         } else {
580                 guint32 idx, segment;
581
582                 _wapi_handle_segment (handle, &segment, &idx);
583                 
584                 _wapi_handle_get_shared_segment (segment)->handles[idx].ref++;
585         
586 #ifdef DEBUG
587                 g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d",
588                            handle,
589                            _wapi_handle_get_shared_segment (segment)->handles[idx].ref);
590 #endif
591         }
592 }
593
594 void _wapi_handle_unref (gpointer handle)
595 {
596         guint32 idx, segment;
597         gboolean destroy;
598
599         _wapi_handle_segment (handle, &segment, &idx);
600         
601         if(shared==TRUE) {
602                 WapiHandleRequest req={0};
603                 WapiHandleResponse resp={0};
604         
605                 req.type=WapiHandleRequestType_Close;
606                 req.u.close.handle=GPOINTER_TO_UINT (handle);
607         
608                 _wapi_daemon_request_response (daemon_sock, &req, &resp);
609                 if(resp.type!=WapiHandleResponseType_Close) {
610                         g_warning (G_GNUC_PRETTY_FUNCTION
611                                    ": bogus daemon response, type %d",
612                                    resp.type);
613                         g_assert_not_reached ();
614                 } else {
615                         destroy=resp.u.close.destroy;
616                 }
617         } else {
618                 _wapi_handle_get_shared_segment (segment)->handles[idx].ref--;
619         
620 #ifdef DEBUG
621                 g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d", handle, _wapi_handle_get_shared_segment (segment)->handles[idx].ref);
622 #endif
623
624                 /* Possible race condition here if another thread refs
625                  * the handle between here and setting the type to
626                  * UNUSED.  I could lock a mutex, but I'm not sure
627                  * that allowing a handle reference to reach 0 isn't
628                  * an application bug anyway.
629                  */
630                 destroy=(_wapi_handle_get_shared_segment (segment)->handles[idx].ref==0);
631         }
632
633         if(destroy==TRUE) {
634 #ifdef DEBUG
635                 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle %p",
636                            handle);
637 #endif
638                 
639                 if(shared==FALSE) {
640                         _wapi_handle_ops_close_shared (handle);
641
642                         mono_mutex_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
643                         pthread_cond_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond);
644                         memset (&_wapi_handle_get_shared_segment (segment)->handles[idx].u, '\0', sizeof(_wapi_handle_get_shared_segment (segment)->handles[idx].u));
645                 
646                 }
647                 else {
648                         mono_mutex_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
649                         pthread_cond_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond);
650                 }
651
652                 _wapi_handle_ops_close_private (handle);
653                 _wapi_handle_get_shared_segment (segment)->handles[idx].type=WAPI_HANDLE_UNUSED;
654         }
655 }
656
657 #define HDRSIZE sizeof(struct _WapiScratchHeader)
658
659 static pthread_mutex_t _wapi_scratch_mutex=PTHREAD_MUTEX_INITIALIZER;
660
661 /* _wapi_scratch_mutex must be held when this function is called in
662  * the non-shared case
663  */
664 static void _wapi_handle_scratch_expand (void)
665 {
666         guint32 old_len, new_len;
667                 
668         old_len=sizeof(struct _WapiHandleScratch) +
669                 _wapi_shared_scratch->data_len;
670         new_len=old_len+_WAPI_SHM_SCRATCH_SIZE;
671                 
672         if(_wapi_shared_scratch->is_shared==TRUE) {
673                 /* expand via mmap() */
674                 _wapi_shared_scratch=_wapi_shm_file_expand (_wapi_shared_scratch, WAPI_SHM_SCRATCH, 0, old_len, new_len);
675         } else {
676                 _wapi_shared_scratch=_wapi_g_renew0 (_wapi_shared_scratch, old_len, new_len);
677         }
678         _wapi_shared_scratch->data_len+=_WAPI_SHM_SCRATCH_SIZE;
679 }
680
681 /* _wapi_scratch_mutex must be held when this function is called in
682  * the non-shared case
683  */
684 static guint32 _wapi_handle_scratch_locate_space (guint32 bytes)
685 {
686         guint32 idx=0, last_idx=0;
687         struct _WapiScratchHeader *hdr, *last_hdr;
688         gboolean last_was_free=FALSE;
689         guchar *storage=_wapi_shared_scratch->scratch_data;
690         
691 #ifdef DEBUG
692         g_message (G_GNUC_PRETTY_FUNCTION
693                    ": looking for %d bytes of scratch space (%d bytes total)",
694                    bytes, _wapi_shared_scratch->data_len);
695 #endif
696         
697         while(idx< _wapi_shared_scratch->data_len) {
698                 hdr=(struct _WapiScratchHeader *)&storage[idx];
699                 
700                 /* Do a simple first-fit allocation, coalescing
701                  * adjacent free blocks as we progress through the
702                  * scratch space
703                  */
704                 if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
705                    hdr->length >= bytes + HDRSIZE) {
706                         /* found space */
707                         guint32 old_length=hdr->length;
708 #ifdef DEBUG
709                         g_message (G_GNUC_PRETTY_FUNCTION ": found suitable free size at %d, length %d", idx, hdr->length);
710 #endif
711
712                         hdr->flags &= ~WAPI_SHM_SCRATCH_FREE;
713                         hdr->length=bytes;
714                         idx += HDRSIZE;
715
716                         /* Put a new header in at the end of the used
717                          * space
718                          */
719                         hdr=(struct _WapiScratchHeader *)&storage[idx+bytes];
720                         hdr->flags |= WAPI_SHM_SCRATCH_FREE;
721                         hdr->length = old_length-bytes-HDRSIZE;
722
723 #ifdef DEBUG
724                         g_message (G_GNUC_PRETTY_FUNCTION ": new header at %d, length %d", idx+bytes, hdr->length);
725 #endif
726                         
727                         /*
728                          * It was memset(0..) when free/made so no need to do it here
729                          */
730
731                         return(idx);
732                 } else if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
733                           last_was_free == FALSE) {
734 #ifdef DEBUG
735                         g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous used)", idx, hdr->length);
736 #endif
737
738                         /* save this point in case we can coalesce it with
739                          * the next block, if that is free.
740                          */
741                         last_was_free=TRUE;
742                         last_idx=idx;
743                         last_hdr=hdr;
744                         idx+=(hdr->length+HDRSIZE);
745                 } else if (hdr->flags & WAPI_SHM_SCRATCH_FREE &&
746                            last_was_free == TRUE) {
747 #ifdef DEBUG
748                         g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous free)", idx, hdr->length);
749 #endif
750
751                         /* This block and the previous are both free,
752                          * so coalesce them
753                          */
754                         last_hdr->length += (hdr->length + HDRSIZE);
755
756                         /* If the new block is now big enough, use it
757                          * (next time round the loop)
758                          */
759                         if(last_hdr->length >= bytes + HDRSIZE) {
760                                 idx=last_idx;
761                         } else {
762                                 /* leave the last free info as it is,
763                                  * in case the next block is also free
764                                  * and can be coalesced too
765                                  */
766                                 idx=last_idx+last_hdr->length+HDRSIZE;
767                         }
768                 } else {
769 #ifdef DEBUG
770                         g_message (G_GNUC_PRETTY_FUNCTION
771                                    ": found used block at %d, length %d", idx,
772                                    hdr->length);
773 #endif
774
775                         /* must be used, try next chunk */
776                         idx+=(hdr->length+HDRSIZE);
777
778                         /* Don't let the coalescing blow away this block */
779                         last_was_free=FALSE;
780
781                         /* But remember where the last block started */
782                         last_idx=idx;
783                 }
784         }
785
786         /* Not enough free space.  last_idx points to the last block.
787          * If it's free, just tack on more space and update the
788          * length.  If it's allocated, it must have fit right into the
789          * available space, so add more space and add a new header
790          * after this block.
791          */
792         _wapi_handle_scratch_expand ();
793         storage=_wapi_shared_scratch->scratch_data;
794         
795         hdr=(struct _WapiScratchHeader *)&storage[last_idx];
796         if(hdr->flags & WAPI_SHM_SCRATCH_FREE) {
797                 hdr->length+=_WAPI_SHM_SCRATCH_SIZE;
798         } else {
799                 idx=(hdr->length+HDRSIZE);
800                 hdr=(struct _WapiScratchHeader *)&storage[idx];
801                 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
802                 hdr->length = _WAPI_SHM_SCRATCH_SIZE-HDRSIZE;
803         }
804
805         /* The caller will try again */
806         return(0);
807 }
808
809 /*
810  * _wapi_handle_scratch_store_internal:
811  * @bytes: Allocate no. bytes
812  *
813  * Like malloc(3) except its for the shared memory segment's scratch
814  * part. Memory block returned is zeroed out.
815  */
816 guint32 _wapi_handle_scratch_store_internal (guint32 bytes, gboolean *remap)
817 {
818         guchar *storage;
819         guint32 idx;
820         struct _WapiScratchHeader *hdr;
821
822 #ifdef DEBUG
823         g_message (G_GNUC_PRETTY_FUNCTION ": storing %d bytes", bytes);
824 #endif
825         
826         *remap=FALSE;
827         
828         if(_wapi_shared_scratch->data_len==0) {
829                 /* Need to expand the data array for the first use */
830 #ifdef DEBUG
831                 g_message (G_GNUC_PRETTY_FUNCTION
832                            ": setting up scratch space");
833 #endif
834
835                 _wapi_handle_scratch_expand ();
836                 *remap=TRUE;
837         }
838
839         storage=_wapi_shared_scratch->scratch_data;
840         hdr=(struct _WapiScratchHeader *)&storage[0];
841         if(hdr->flags==0 && hdr->length==0) {
842                 /* Need to initialise scratch data */
843                 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
844                 hdr->length = _wapi_shared_scratch->data_len - HDRSIZE;
845         }
846
847         idx=_wapi_handle_scratch_locate_space (bytes);
848         if(idx==0) {
849                 /* Some more space will have been allocated, so try again */
850 #ifdef DEBUG
851                 g_message (G_GNUC_PRETTY_FUNCTION ": trying again");
852 #endif
853
854                 idx=_wapi_handle_scratch_locate_space (bytes);
855                 *remap=TRUE;
856         }
857         
858         return(idx);
859 }
860
861 guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes)
862 {
863         guint32 idx, store_bytes;
864         gboolean remap;
865
866 #ifdef DEBUG
867         g_message (G_GNUC_PRETTY_FUNCTION ": storing %d bytes", bytes);
868 #endif
869
870         /* No point storing no data */
871         if(bytes==0) {
872                 return(0);
873         }
874
875         /* Align bytes to 32 bits (needed for sparc at least) */
876         store_bytes = (((bytes) + 3) & (~3));
877
878         pthread_mutex_lock (&_wapi_scratch_mutex);
879
880         if(shared==TRUE) {
881                 WapiHandleRequest scratch={0};
882                 WapiHandleResponse scratch_resp={0};
883                 guint32 old_len=sizeof(struct _WapiHandleScratch) +
884                         _wapi_shared_scratch->data_len;
885                 
886                 scratch.type=WapiHandleRequestType_Scratch;
887                 scratch.u.scratch.length=store_bytes;
888         
889                 _wapi_daemon_request_response (daemon_sock, &scratch,
890                                                &scratch_resp);
891         
892                 if(scratch_resp.type==WapiHandleResponseType_Scratch) {
893                         idx=scratch_resp.u.scratch.idx;
894                         remap=scratch_resp.u.scratch.remap;
895                 } else {
896                         g_warning (G_GNUC_PRETTY_FUNCTION
897                                    ": bogus daemon response, type %d",
898                                    scratch_resp.type);
899                         g_assert_not_reached ();
900                 }
901         
902                 if(remap==TRUE) {
903                         munmap (_wapi_shared_scratch, old_len);
904                         _wapi_shared_scratch=_wapi_shm_file_map (WAPI_SHM_SCRATCH, 0, NULL, NULL);
905                 }
906         } else {
907                 idx=_wapi_handle_scratch_store_internal (store_bytes, &remap);
908                 if(idx==0) {
909                         /* Failed to allocate space */
910                         pthread_mutex_unlock (&_wapi_scratch_mutex);
911                         return(0);
912                 }
913         }
914
915 #ifdef DEBUG
916         g_message (G_GNUC_PRETTY_FUNCTION
917                    ": stored [%s] at %d (len %d, aligned len %d)",
918                    (char *)data, idx, bytes, store_bytes);
919 #endif
920         
921         memcpy (&_wapi_shared_scratch->scratch_data[idx], data, bytes);
922
923         pthread_mutex_unlock (&_wapi_scratch_mutex);
924         
925         return(idx);
926 }
927
928 guint32 _wapi_handle_scratch_store_string_array (gchar **data)
929 {
930         guint32 *stored_strings, count=0, i, idx;
931         gchar **strings;
932         
933         /* No point storing no data */
934         if(data==NULL) {
935                 return(0);
936         }
937
938         strings=data;
939         while(*strings!=NULL) {
940                 count++;
941                 strings++;
942         }
943         
944 #ifdef DEBUG
945         g_message (G_GNUC_PRETTY_FUNCTION ": %d strings to store", count);
946 #endif
947         
948         if(count==0) {
949                 return(0);
950         }
951
952         /* stored_strings[0] is the count */
953         stored_strings=g_new0 (guint32, count+1);
954         stored_strings[0]=count;
955         
956         strings=data;
957         for(i=0; i<count; i++) {
958                 stored_strings[i+1]=_wapi_handle_scratch_store (strings[i], strlen (strings[i]));
959         }
960
961         idx=_wapi_handle_scratch_store (stored_strings,
962                                         sizeof(guint32)*(count+1));
963         
964         return(idx);
965 }
966
967 gpointer _wapi_handle_scratch_lookup (guint32 idx)
968 {
969         struct _WapiScratchHeader *hdr;
970         gpointer ret;
971         guchar *storage;
972         
973         if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
974                 return(NULL);
975         }
976
977         pthread_mutex_lock (&_wapi_scratch_mutex);
978         
979         storage=_wapi_shared_scratch->scratch_data;
980         
981         hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
982         ret=g_malloc0 (hdr->length+1);
983         memcpy (ret, &storage[idx], hdr->length);
984
985         pthread_mutex_unlock (&_wapi_scratch_mutex);
986
987         return(ret);
988 }
989
990 gchar **_wapi_handle_scratch_lookup_string_array (guint32 idx)
991 {
992         gchar **strings;
993         guint32 *stored_strings;
994         guint32 count, i;
995         
996         if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
997                 return(NULL);
998         }
999
1000         stored_strings=_wapi_handle_scratch_lookup (idx);
1001         if(stored_strings==NULL) {
1002                 return(NULL);
1003         }
1004         
1005         /* stored_strings[0] is the number of strings, the index of
1006          * each string follows
1007          */
1008         count=stored_strings[0];
1009         
1010 #ifdef DEBUG
1011         g_message (G_GNUC_PRETTY_FUNCTION
1012                    ": looking up an array of %d strings", count);
1013 #endif
1014         
1015         /* NULL-terminate the array */
1016         strings=g_new0 (gchar *, count+1);
1017         
1018         for(i=0; i<count; i++) {
1019                 strings[i]=_wapi_handle_scratch_lookup (stored_strings[i+1]);
1020
1021 #ifdef DEBUG
1022                 g_message (G_GNUC_PRETTY_FUNCTION ": string %d is [%s]", i,
1023                            strings[i]);
1024 #endif
1025         }
1026
1027         g_free (stored_strings);
1028         
1029         return(strings);
1030 }
1031
1032 /*
1033  * _wapi_handle_scratch_delete_internal:
1034  * @idx: Index to free block
1035  *
1036  * Like free(3) except its for the shared memory segment's scratch
1037  * part.
1038  */
1039 void _wapi_handle_scratch_delete_internal (guint32 idx)
1040 {
1041         struct _WapiScratchHeader *hdr;
1042         guchar *storage;
1043         
1044         if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
1045                 return;
1046         }
1047
1048         pthread_mutex_lock (&_wapi_scratch_mutex);
1049         
1050         storage=_wapi_shared_scratch->scratch_data;
1051         
1052         hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
1053         memset (&storage[idx], '\0', hdr->length);
1054         hdr->flags |= WAPI_SHM_SCRATCH_FREE;
1055         
1056         /* We could coalesce forwards here if the next block is also
1057          * free, but the _store() function will do that anyway.
1058          */
1059
1060         pthread_mutex_unlock (&_wapi_scratch_mutex);
1061 }
1062
1063 void _wapi_handle_scratch_delete (guint32 idx)
1064 {
1065         if(shared==TRUE) {
1066                 WapiHandleRequest scratch_free={0};
1067                 WapiHandleResponse scratch_free_resp={0};
1068         
1069                 scratch_free.type=WapiHandleRequestType_ScratchFree;
1070                 scratch_free.u.scratch_free.idx=idx;
1071         
1072                 _wapi_daemon_request_response (daemon_sock, &scratch_free,
1073                                                &scratch_free_resp);
1074         
1075                 if(scratch_free_resp.type!=WapiHandleResponseType_ScratchFree) {
1076                         g_warning (G_GNUC_PRETTY_FUNCTION
1077                                    ": bogus daemon response, type %d",
1078                                    scratch_free_resp.type);
1079                         g_assert_not_reached ();
1080                 }
1081         } else {
1082                 _wapi_handle_scratch_delete_internal (idx);
1083         }
1084 }
1085
1086 void _wapi_handle_scratch_delete_string_array (guint32 idx)
1087 {
1088         guint32 *stored_strings;
1089         guint32 count, i;
1090         
1091         stored_strings=_wapi_handle_scratch_lookup (idx);
1092         if(stored_strings==NULL) {
1093                 return;
1094         }
1095         
1096         /* stored_strings[0] is the number of strings, the index of
1097          * each string follows
1098          */
1099         count=stored_strings[0];
1100         
1101 #ifdef DEBUG
1102         g_message (G_GNUC_PRETTY_FUNCTION ": deleting an array of %d strings",
1103                    count);
1104 #endif
1105         
1106         for(i=1; i<count; i++) {
1107                 _wapi_handle_scratch_delete (stored_strings[i]);
1108         }
1109         
1110         _wapi_handle_scratch_delete (idx);
1111
1112         g_free (stored_strings);
1113 }
1114
1115 void _wapi_handle_register_capabilities (WapiHandleType type,
1116                                          WapiHandleCapability caps)
1117 {
1118         handle_caps[type]=caps;
1119 }
1120
1121 gboolean _wapi_handle_test_capabilities (gpointer handle,
1122                                          WapiHandleCapability caps)
1123 {
1124         guint32 idx, segment;
1125         WapiHandleType type;
1126
1127         _wapi_handle_segment (handle, &segment, &idx);
1128         
1129         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1130
1131 #ifdef DEBUG
1132         g_message (G_GNUC_PRETTY_FUNCTION ": testing 0x%x against 0x%x (%d)",
1133                    handle_caps[type], caps, handle_caps[type] & caps);
1134 #endif
1135         
1136         return((handle_caps[type] & caps)!=0);
1137 }
1138
1139 void _wapi_handle_ops_close_shared (gpointer handle)
1140 {
1141         guint32 idx, segment;
1142         WapiHandleType type;
1143
1144         _wapi_handle_segment (handle, &segment, &idx);
1145         
1146         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1147
1148         if(handle_ops[type]!=NULL && handle_ops[type]->close_shared!=NULL) {
1149                 handle_ops[type]->close_shared (handle);
1150         }
1151 }
1152
1153 void _wapi_handle_ops_close_private (gpointer handle)
1154 {
1155         guint32 idx, segment;
1156         WapiHandleType type;
1157
1158         _wapi_handle_segment (handle, &segment, &idx);
1159
1160         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1161
1162         /* When a handle in the process of being destroyed the shared
1163          * type has already been set to UNUSED
1164          */
1165         if(type==WAPI_HANDLE_UNUSED && _wapi_private_data!=NULL) {
1166                 type=_wapi_handle_get_private_segment (segment)->handles[idx].type;
1167         }
1168
1169         if(handle_ops[type]!=NULL && handle_ops[type]->close_private!=NULL) {
1170                 handle_ops[type]->close_private (handle);
1171         }
1172 }
1173
1174 void _wapi_handle_ops_signal (gpointer handle)
1175 {
1176         guint32 idx, segment;
1177         WapiHandleType type;
1178
1179         _wapi_handle_segment (handle, &segment, &idx);
1180
1181         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1182
1183         if(handle_ops[type]!=NULL && handle_ops[type]->signal!=NULL) {
1184                 handle_ops[type]->signal (handle);
1185         }
1186 }
1187
1188 void _wapi_handle_ops_own (gpointer handle)
1189 {
1190         guint32 idx, segment;
1191         WapiHandleType type;
1192
1193         _wapi_handle_segment (handle, &segment, &idx);
1194         
1195         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1196
1197         if(handle_ops[type]!=NULL && handle_ops[type]->own_handle!=NULL) {
1198                 handle_ops[type]->own_handle (handle);
1199         }
1200 }
1201
1202 gboolean _wapi_handle_ops_isowned (gpointer handle)
1203 {
1204         guint32 idx, segment;
1205         WapiHandleType type;
1206
1207         _wapi_handle_segment (handle, &segment, &idx);
1208         
1209         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1210
1211         if(handle_ops[type]!=NULL && handle_ops[type]->is_owned!=NULL) {
1212                 return(handle_ops[type]->is_owned (handle));
1213         } else {
1214                 return(FALSE);
1215         }
1216 }
1217
1218 /**
1219  * CloseHandle:
1220  * @handle: The handle to release
1221  *
1222  * Closes and invalidates @handle, releasing any resources it
1223  * consumes.  When the last handle to a temporary or non-persistent
1224  * object is closed, that object can be deleted.  Closing the same
1225  * handle twice is an error.
1226  *
1227  * Return value: %TRUE on success, %FALSE otherwise.
1228  */
1229 gboolean CloseHandle(gpointer handle)
1230 {
1231         _wapi_handle_unref (handle);
1232         
1233         return(TRUE);
1234 }
1235
1236 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1237                                                gpointer *handles,
1238                                                gboolean waitall,
1239                                                guint32 *retcount,
1240                                                guint32 *lowest)
1241 {
1242         guint32 count, i, iter=0;
1243         gboolean ret;
1244         
1245         /* Lock all the handles, with backoff */
1246 again:
1247         for(i=0; i<numhandles; i++) {
1248                 guint32 idx, segment;
1249                 
1250                 _wapi_handle_segment (handles[i], &segment, &idx);
1251                 
1252 #ifdef DEBUG
1253                 g_message (G_GNUC_PRETTY_FUNCTION ": attempting to lock %p",
1254                            handles[i]);
1255 #endif
1256
1257                 ret=mono_mutex_trylock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
1258                 if(ret!=0) {
1259                         /* Bummer */
1260                         struct timespec sleepytime;
1261                         
1262 #ifdef DEBUG
1263                         g_message (G_GNUC_PRETTY_FUNCTION ": attempt failed for %p", handles[i]);
1264 #endif
1265
1266                         while(i--) {
1267                                 _wapi_handle_segment (handles[i], &segment, &idx);
1268                                 mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
1269                         }
1270
1271                         /* If iter ever reaches 100 the nanosleep will
1272                          * return EINVAL immediately, but we have a
1273                          * design flaw if that happens.
1274                          */
1275                         iter++;
1276                         if(iter==100) {
1277                                 g_warning (G_GNUC_PRETTY_FUNCTION
1278                                            ": iteration overflow!");
1279                                 iter=1;
1280                         }
1281                         
1282                         sleepytime.tv_sec=0;
1283                         sleepytime.tv_nsec=10000000 * iter;     /* 10ms*iter */
1284                         
1285 #ifdef DEBUG
1286                         g_message (G_GNUC_PRETTY_FUNCTION
1287                                    ": Backing off for %d ms", iter*10);
1288 #endif
1289                         nanosleep (&sleepytime, NULL);
1290                         
1291                         goto again;
1292                 }
1293         }
1294         
1295 #ifdef DEBUG
1296         g_message (G_GNUC_PRETTY_FUNCTION ": Locked all handles");
1297 #endif
1298
1299         count=0;
1300         *lowest=numhandles;
1301         
1302         for(i=0; i<numhandles; i++) {
1303                 guint32 idx, segment;
1304
1305                 _wapi_handle_segment (handles[i], &segment, &idx);
1306                 
1307 #ifdef DEBUG
1308                 g_message (G_GNUC_PRETTY_FUNCTION ": Checking handle %p",
1309                            handles[i]);
1310 #endif
1311
1312                 if(((_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_OWN)==TRUE) &&
1313                     (_wapi_handle_ops_isowned (handles[i])==TRUE)) ||
1314                    (_wapi_handle_get_shared_segment (segment)->handles[idx].signalled==TRUE)) {
1315                         count++;
1316                         
1317 #ifdef DEBUG
1318                         g_message (G_GNUC_PRETTY_FUNCTION
1319                                    ": Handle %p signalled", handles[i]);
1320 #endif
1321                         if(*lowest>i) {
1322                                 *lowest=i;
1323                         }
1324                 }
1325         }
1326         
1327 #ifdef DEBUG
1328         g_message (G_GNUC_PRETTY_FUNCTION ": %d event handles signalled",
1329                    count);
1330 #endif
1331
1332         if((waitall==TRUE && count==numhandles) ||
1333            (waitall==FALSE && count>0)) {
1334                 ret=TRUE;
1335         } else {
1336                 ret=FALSE;
1337         }
1338         
1339 #ifdef DEBUG
1340         g_message (G_GNUC_PRETTY_FUNCTION ": Returning %d", ret);
1341 #endif
1342
1343         *retcount=count;
1344         
1345         return(ret);
1346 }
1347
1348 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1349 {
1350         guint32 i;
1351         
1352         for(i=0; i<numhandles; i++) {
1353                 guint32 idx, segment;
1354
1355                 _wapi_handle_segment (handles[i], &segment, &idx);
1356
1357 #ifdef DEBUG
1358                 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p",
1359                            handles[i]);
1360 #endif
1361
1362                 mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
1363         }
1364 }
1365
1366 /* Process-shared handles (currently only process and thread handles
1367  * are allowed, and they only work because once signalled they can't
1368  * become unsignalled) are waited for by one process and signalled by
1369  * another.  Without process-shared conditions, the waiting process
1370  * will block forever.  To get around this, the four handle waiting
1371  * functions use a short timeout when _POSIX_THREAD_PROCESS_SHARED is
1372  * not available.  They also return "success" if the fake timeout
1373  * expired, and let the caller check signal status.
1374  */
1375 int _wapi_handle_wait_signal (void)
1376 {
1377 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1378         return(mono_cond_wait (&_wapi_handle_get_shared_segment (0)->signal_cond,
1379                                &_wapi_handle_get_shared_segment (0)->signal_mutex));
1380 #else
1381         struct timespec fake_timeout;
1382         int ret;
1383         
1384         _wapi_calc_timeout (&fake_timeout, 100);
1385
1386         ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
1387                                  &_wapi_handle_get_private_segment (0)->signal_mutex,
1388                                  &fake_timeout);
1389         if(ret==ETIMEDOUT) {
1390                 ret=0;
1391         }
1392
1393         return(ret);
1394 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1395 }
1396
1397 int _wapi_handle_timedwait_signal (struct timespec *timeout)
1398 {
1399 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1400         return(mono_cond_timedwait (&_wapi_handle_get_shared_segment (0)->signal_cond,
1401                                     &_wapi_handle_get_shared_segment (0)->signal_mutex,
1402                                     timeout));
1403 #else
1404         struct timespec fake_timeout;
1405         int ret;
1406         
1407         _wapi_calc_timeout (&fake_timeout, 100);
1408         
1409         if((fake_timeout.tv_sec>timeout->tv_sec) ||
1410            (fake_timeout.tv_sec==timeout->tv_sec &&
1411             fake_timeout.tv_nsec > timeout->tv_nsec)) {
1412                 /* Real timeout is less than 100ms time */
1413                 ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
1414                                          &_wapi_handle_get_private_segment (0)->signal_mutex,
1415                                          timeout);
1416         } else {
1417                 ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
1418                                          &_wapi_handle_get_private_segment (0)->signal_mutex,
1419                                          &fake_timeout);
1420                 if(ret==ETIMEDOUT) {
1421                         ret=0;
1422                 }
1423         }
1424         
1425         return(ret);
1426 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1427 }
1428
1429 int _wapi_handle_wait_signal_handle (gpointer handle)
1430 {
1431 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1432         guint32 idx, segment;
1433
1434         _wapi_handle_segment (handle, &segment, &idx);
1435         
1436         return(mono_cond_wait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1437                                &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex));
1438 #else
1439         guint32 idx, segment;
1440         struct timespec fake_timeout;
1441         int ret;
1442         
1443         _wapi_handle_segment (handle, &segment, &idx);
1444         _wapi_calc_timeout (&fake_timeout, 100);
1445         
1446         ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1447                                  &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1448                                  &fake_timeout);
1449         if(ret==ETIMEDOUT) {
1450                 ret=0;
1451         }
1452
1453         return(ret);
1454 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1455 }
1456
1457 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1458                                           struct timespec *timeout)
1459 {
1460 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1461         guint32 idx, segment;
1462
1463         _wapi_handle_segment (handle, &segment, &idx);
1464         
1465         return(mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1466                                     &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1467                                     timeout));
1468 #else
1469         guint32 idx, segment;
1470         struct timespec fake_timeout;
1471         int ret;
1472         
1473         _wapi_handle_segment (handle, &segment, &idx);
1474         _wapi_calc_timeout (&fake_timeout, 100);
1475         
1476         if((fake_timeout.tv_sec>timeout->tv_sec) ||
1477            (fake_timeout.tv_sec==timeout->tv_sec &&
1478             fake_timeout.tv_nsec > timeout->tv_nsec)) {
1479                 /* Real timeout is less than 100ms time */
1480                 ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1481                                          &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1482                                          timeout);
1483         } else {
1484                 ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1485                                          &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1486                                          &fake_timeout);
1487                 if(ret==ETIMEDOUT) {
1488                         ret=0;
1489                 }
1490         }
1491         
1492         return(ret);
1493 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1494 }
1495
1496 gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
1497                                     gboolean inherit, guint32 flags,
1498                                     gpointer stdin_handle,
1499                                     gpointer stdout_handle,
1500                                     gpointer stderr_handle,
1501                                     gpointer *process_handle,
1502                                     gpointer *thread_handle, guint32 *pid,
1503                                     guint32 *tid)
1504 {
1505         WapiHandleRequest fork_proc={0};
1506         WapiHandleResponse fork_proc_resp={0};
1507         int in_fd, out_fd, err_fd;
1508         
1509         if(shared!=TRUE) {
1510                 return(FALSE);
1511         }
1512
1513         fork_proc.type=WapiHandleRequestType_ProcessFork;
1514         fork_proc.u.process_fork.cmd=cmd;
1515         fork_proc.u.process_fork.env=env;
1516         fork_proc.u.process_fork.dir=dir;
1517         fork_proc.u.process_fork.stdin_handle=GPOINTER_TO_UINT (stdin_handle);
1518         fork_proc.u.process_fork.stdout_handle=GPOINTER_TO_UINT (stdout_handle);
1519         fork_proc.u.process_fork.stderr_handle=GPOINTER_TO_UINT (stderr_handle);
1520         fork_proc.u.process_fork.inherit=inherit;
1521         fork_proc.u.process_fork.flags=flags;
1522         
1523         in_fd=_wapi_file_handle_to_fd (stdin_handle);
1524         out_fd=_wapi_file_handle_to_fd (stdout_handle);
1525         err_fd=_wapi_file_handle_to_fd (stderr_handle);
1526
1527         if(in_fd==-1 || out_fd==-1 || err_fd==-1) {
1528                 /* We were given duff handles */
1529                 /* FIXME: error code */
1530                 return(FALSE);
1531         }
1532         
1533         _wapi_daemon_request_response_with_fds (daemon_sock, &fork_proc,
1534                                                 &fork_proc_resp, in_fd,
1535                                                 out_fd, err_fd);
1536         if(fork_proc_resp.type==WapiHandleResponseType_ProcessFork) {
1537                 *process_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.process_handle);
1538                 *thread_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.thread_handle);
1539                 *pid=fork_proc_resp.u.process_fork.pid;
1540                 *tid=fork_proc_resp.u.process_fork.tid;
1541
1542                 /* If there was an internal error, the handles will be
1543                  * 0.  If there was an error forking or execing, the
1544                  * handles will have values, and process_handle's
1545                  * exec_errno will be set, and the handle will be
1546                  * signalled immediately.
1547                  */
1548                 if(process_handle==0 || thread_handle==0) {
1549                         return(FALSE);
1550                 } else {
1551                         return(TRUE);
1552                 }
1553         } else {
1554                 g_warning (G_GNUC_PRETTY_FUNCTION
1555                            ": bogus daemon response, type %d",
1556                            fork_proc_resp.type);
1557                 g_assert_not_reached ();
1558         }
1559         
1560         return(FALSE);
1561 }