2 * handles.c: Generic and internal operations on handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
16 #include <sys/types.h>
17 #include <sys/socket.h>
21 #include <mono/os/gc_wrapper.h>
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>
32 #undef HEAVY_DEBUG /* This will print handle counts on every handle created */
34 /* Shared threads don't seem to work yet */
35 #undef _POSIX_THREAD_PROCESS_SHARED
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
44 * This is further complicated by the second attempt to start the
45 * daemon if the connect() fails.
47 static gboolean shared=FALSE;
49 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
50 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
64 static int daemon_sock;
66 static pthread_mutexattr_t mutex_shared_attr;
67 static pthread_condattr_t cond_shared_attr;
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;
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
78 guint32 _wapi_shm_mapped_segments;
80 static void shared_init (void)
82 struct sockaddr_un shared_socket_address;
83 gboolean tried_once=FALSE;
87 _wapi_shared_data=g_new0 (struct _WapiHandleShared_list *, 1);
88 _wapi_private_data=g_new0 (struct _WapiHandlePrivate_list *, 1);
92 #ifndef DISABLE_SHARED_HANDLES
93 if(getenv ("MONO_DISABLE_SHM"))
97 #ifndef DISABLE_SHARED_HANDLES
99 /* Ensure that shared==FALSE while _wapi_shm_attach()
104 shared=_wapi_shm_attach (&_wapi_shared_data[0],
105 &_wapi_shared_scratch);
108 "Failed to attach shared memory! "
109 "Falling back to non-shared handles\n"
110 "See: http://www.go-mono.com/issues.html#wapi for details");
112 #endif /* DISABLE_SHARED_HANDLES */
117 daemon_sock=socket (PF_UNIX, SOCK_STREAM, 0);
118 shared_socket_address.sun_family=AF_UNIX;
119 memcpy (shared_socket_address.sun_path,
120 _wapi_shared_data[0]->daemon, MONO_SIZEOF_SUNPATH);
121 ret=connect (daemon_sock,
122 (struct sockaddr *)&shared_socket_address,
123 sizeof(struct sockaddr_un));
125 if(tried_once==TRUE) {
126 g_warning (G_GNUC_PRETTY_FUNCTION
127 ": connect to daemon failed: %s",
129 /* Fall back to private handles */
132 /* It's possible that the daemon
133 * crashed without destroying the
134 * shared memory segment (thus fooling
135 * subsequent processes into thinking
136 * the daemon is still active).
138 * Destroy the shared memory segment
139 * and try once more. This won't
140 * break running apps, but no new apps
141 * will be able to see the current
142 * shared memory segment.
145 _wapi_shm_destroy ();
154 g_message (G_GNUC_PRETTY_FUNCTION
155 ": Using process-private handles");
157 _wapi_shared_data[0]=g_new0 (struct _WapiHandleShared_list, 1);
158 _wapi_shared_data[0]->num_segments=1;
160 _wapi_shared_scratch=g_new0 (struct _WapiHandleScratch, 1);
162 _wapi_private_data[0]=g_new0 (struct _WapiHandlePrivate_list, 1);
163 _wapi_shm_mapped_segments=1;
165 thr_ret = pthread_mutexattr_init (&mutex_shared_attr);
166 g_assert (thr_ret == 0);
168 thr_ret = pthread_condattr_init (&cond_shared_attr);
169 g_assert (thr_ret == 0);
171 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
172 thr_ret = pthread_mutexattr_setpshared (&mutex_shared_attr,
173 PTHREAD_PROCESS_SHARED);
174 g_assert (thr_ret == 0);
176 thr_ret = pthread_condattr_setpshared (&cond_shared_attr,
177 PTHREAD_PROCESS_SHARED);
178 g_assert (thr_ret == 0);
180 thr_ret = pthread_cond_init(&_wapi_private_data[0]->signal_cond, NULL);
181 g_assert (thr_ret == 0);
183 thr_ret = mono_mutex_init(&_wapi_private_data[0]->signal_mutex, NULL);
184 g_assert (thr_ret == 0);
190 print_handle_count (gint mask)
192 gint *count, num_handles;
194 static const gchar *names [] = {"WAPI_HANDLE_UNUSED",
196 "WAPI_HANDLE_CONSOLE",
197 "WAPI_HANDLE_THREAD",
201 "WAPI_HANDLE_SOCKET",
203 "WAPI_HANDLE_PROCESS",
208 num_handles=_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT;
209 count=g_new0 (gint, num_handles);
211 for (i = 1; i < num_handles; i++) {
212 struct _WapiHandleShared *shared;
213 guint32 segment, idx;
215 _wapi_handle_segment (GUINT_TO_POINTER (i), &segment, &idx);
216 _wapi_handle_ensure_mapped (segment);
218 shared = &_wapi_handle_get_shared_segment (segment)->handles[idx];
219 count [shared->type]++;
222 for (i = 0; i < num_handles; i++)
223 if ((i & mask) == i) /* Always prints the UNUSED count */
224 g_print ("%s: %d\n", names [i], count [i]);
228 #endif /* HEAVY_DEBUG */
231 * _wapi_handle_new_internal:
232 * @type: Init handle to this type
234 * Search for a free handle and initialize it. Return the handle on
235 * success and 0 on failure.
237 guint32 _wapi_handle_new_internal (WapiHandleType type)
239 guint32 segment, idx;
241 static guint32 last=1;
244 /* A linear scan should be fast enough. Start from the last
245 * allocation, assuming that handles are allocated more often
246 * than they're freed. Leave 0 (NULL) as a guard
249 print_handle_count (0xFFF);
252 _wapi_handle_segment (GUINT_TO_POINTER (last), &segment, &idx);
253 for(i=segment; i<_wapi_handle_get_shared_segment (0)->num_segments;
259 for(j=idx; j<_WAPI_HANDLES_PER_SEGMENT; j++) {
260 struct _WapiHandleShared *shared;
262 /* Make sure we dont try and assign handle 0 */
267 shared=&_wapi_handle_get_shared_segment (i)->handles[j];
269 if(shared->type==WAPI_HANDLE_UNUSED) {
270 last=(_wapi_handle_index (i, j)+1) % (_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT);
272 shared->signalled=FALSE;
273 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
274 thr_ret = mono_mutex_init (&shared->signal_mutex, &mutex_shared_attr);
275 g_assert (thr_ret == 0);
277 thr_ret = pthread_cond_init (&shared->signal_cond, &cond_shared_attr);
278 g_assert (thr_ret == 0);
280 thr_ret = pthread_cond_init(&shared->signal_cond, NULL);
281 g_assert (thr_ret == 0);
283 thr_ret = mono_mutex_init(&shared->signal_mutex, NULL);
284 g_assert (thr_ret == 0);
287 return(_wapi_handle_index (i, j));
293 /* Try again from the beginning */
298 /* Will need a new segment. The caller will sort it out */
303 gpointer _wapi_handle_new (WapiHandleType type)
305 static mono_once_t shared_init_once = MONO_ONCE_INIT;
306 static pthread_mutex_t scan_mutex=PTHREAD_MUTEX_INITIALIZER;
307 guint32 handle_idx = 0, idx, segment;
309 WapiHandleRequest new={0};
310 WapiHandleResponse new_resp={0};
312 gboolean tried_collect=FALSE;
316 mono_once (&shared_init_once, shared_init);
320 new.type=WapiHandleRequestType_New;
323 _wapi_daemon_request_response (daemon_sock, &new, &new_resp);
325 if (new_resp.type==WapiHandleResponseType_New) {
326 handle_idx=new_resp.u.new.handle;
328 g_warning (G_GNUC_PRETTY_FUNCTION
329 ": bogus daemon response, type %d",
331 g_assert_not_reached ();
334 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
335 (void *)&scan_mutex);
336 thr_ret = pthread_mutex_lock (&scan_mutex);
337 g_assert (thr_ret == 0);
339 handle_idx=_wapi_handle_new_internal (type);
341 /* Try and get a new segment, and have another go */
342 segment=_wapi_handle_get_shared_segment (0)->num_segments;
343 _wapi_handle_ensure_mapped (segment);
345 if(_wapi_handle_get_shared_segment (segment)!=NULL) {
346 /* Got a new segment */
347 _wapi_handle_get_shared_segment (0)->num_segments++;
348 handle_idx=_wapi_handle_new_internal (type);
350 /* Map failed. Just return 0 meaning
356 _wapi_handle_segment (GUINT_TO_POINTER (handle_idx), &segment, &idx);
357 _wapi_handle_get_shared_segment (segment)->handles[idx].ref++;
359 thr_ret = pthread_mutex_unlock (&scan_mutex);
360 g_assert (thr_ret == 0);
361 pthread_cleanup_pop (0);
365 g_warning (G_GNUC_PRETTY_FUNCTION ": Ran out of handles!");
368 /* See if we can reclaim some handles by forcing a GC
371 if(tried_collect==FALSE) {
372 g_warning (G_GNUC_PRETTY_FUNCTION
373 ": Seeing if GC collection helps...");
374 GC_gcollect (); /* FIXME: we should wait for finalizers to be called */
378 g_warning (G_GNUC_PRETTY_FUNCTION
379 ": didn't help, returning error");
383 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
386 _wapi_handle_segment (GUINT_TO_POINTER (handle_idx), &segment, &idx);
387 _wapi_handle_ensure_mapped (segment);
389 if(_wapi_private_data!=NULL) {
390 _wapi_handle_get_private_segment (segment)->handles[idx].type=type;
393 #if !defined(_POSIX_THREAD_PROCESS_SHARED) || _POSIX_THREAD_PROCESS_SHARED == -1
394 thr_ret = mono_mutex_init (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex, &mutex_shared_attr);
395 g_assert (thr_ret == 0);
397 thr_ret = pthread_cond_init (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond, &cond_shared_attr);
398 g_assert (thr_ret == 0);
400 handle=GUINT_TO_POINTER (handle_idx);
403 g_message (G_GNUC_PRETTY_FUNCTION ": Allocated new handle %p", handle);
409 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
410 gpointer *shared, gpointer *private)
412 struct _WapiHandleShared *shared_handle_data;
413 struct _WapiHandlePrivate *private_handle_data = NULL;
417 _wapi_handle_segment (handle, &segment, &idx);
418 _wapi_handle_ensure_mapped (segment);
420 shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
423 *shared=&shared_handle_data->u;
427 private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
429 *private=&private_handle_data->u;
432 if(shared_handle_data->type!=type) {
433 /* If shared type is UNUSED, see if the private type
434 * matches what we are looking for - this can happen
435 * when the handle is being destroyed and the
436 * close_private function is looking up the private
439 if(shared_handle_data->type==WAPI_HANDLE_UNUSED &&
440 (private!=NULL && private_handle_data->type==type)) {
450 gpointer _wapi_search_handle (WapiHandleType type,
451 gboolean (*check)(gpointer test, gpointer user),
453 gpointer *shared, gpointer *private)
455 struct _WapiHandleShared *shared_handle_data;
456 struct _WapiHandlePrivate *private_handle_data;
457 guint32 i, segment, idx;
459 for(i=1; i<_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT; i++) {
460 struct _WapiHandleShared *shared;
462 _wapi_handle_segment (GUINT_TO_POINTER (i), &segment, &idx);
463 _wapi_handle_ensure_mapped (segment);
465 shared=&_wapi_handle_get_shared_segment (segment)->handles[idx];
467 if(shared->type==type) {
468 if(check (GUINT_TO_POINTER (i), user_data)==TRUE) {
474 if(i==_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT) {
475 return(GUINT_TO_POINTER (0));
479 shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
481 *shared=&shared_handle_data->u;
485 private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
487 *private=&private_handle_data->u;
490 return(GUINT_TO_POINTER (i));
493 gpointer _wapi_search_handle_namespace (WapiHandleType type,
494 gchar *utf8_name, gpointer *shared,
497 struct _WapiHandleShared *shared_handle_data;
498 struct _WapiHandlePrivate *private_handle_data;
499 guint32 i, segment, idx;
502 g_message (G_GNUC_PRETTY_FUNCTION
503 ": Lookup for handle named [%s] type %d", utf8_name, type);
506 for(i=1; i<_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT; i++) {
507 struct _WapiHandleShared *shared;
509 _wapi_handle_segment (GUINT_TO_POINTER (i), &segment, &idx);
510 _wapi_handle_ensure_mapped (segment);
512 shared=&_wapi_handle_get_shared_segment (segment)->handles[idx];
514 /* Check mutex, event, semaphore, timer, job and file-mapping
515 * object names. So far only mutex is implemented.
517 if(_WAPI_SHARED_NAMESPACE (shared->type)) {
519 WapiSharedNamespace *sharedns;
522 g_message (G_GNUC_PRETTY_FUNCTION ": found a shared namespace handle at 0x%x (type %d)", i, shared->type);
525 shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
526 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
530 lookup_name=_wapi_handle_scratch_lookup (
534 g_message (G_GNUC_PRETTY_FUNCTION
535 ": handle 0x%x is unnamed", i);
540 if(lookup_name==NULL) {
542 g_message (G_GNUC_PRETTY_FUNCTION
543 ": couldn't find handle 0x%x name",
550 g_message (G_GNUC_PRETTY_FUNCTION ": name is [%s]",
554 if(strcmp (lookup_name, utf8_name)==0) {
555 if(shared->type!=type) {
556 /* Its the wrong type, so fail now */
558 g_message (G_GNUC_PRETTY_FUNCTION ": handle 0x%x matches name but is wrong type: %d", i, shared->type);
560 return(_WAPI_HANDLE_INVALID);
562 /* fall through so we can fill
566 g_message (G_GNUC_PRETTY_FUNCTION ": handle 0x%x matches name and type", i);
574 if(i==_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT) {
575 return(GUINT_TO_POINTER (0));
579 shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
581 *shared=&shared_handle_data->u;
585 private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
587 *private=&private_handle_data->u;
590 return(GUINT_TO_POINTER (i));
593 void _wapi_handle_ref (gpointer handle)
596 WapiHandleRequest req={0};
597 WapiHandleResponse resp={0};
599 req.type=WapiHandleRequestType_Open;
600 req.u.open.handle=GPOINTER_TO_UINT (handle);
602 _wapi_daemon_request_response (daemon_sock, &req, &resp);
603 if(resp.type!=WapiHandleResponseType_Open) {
604 g_warning (G_GNUC_PRETTY_FUNCTION
605 ": bogus daemon response, type %d",
607 g_assert_not_reached ();
610 guint32 idx, segment;
612 _wapi_handle_segment (handle, &segment, &idx);
614 _wapi_handle_get_shared_segment (segment)->handles[idx].ref++;
617 g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d",
619 _wapi_handle_get_shared_segment (segment)->handles[idx].ref);
624 /* The handle must not be locked on entry to this function */
625 void _wapi_handle_unref (gpointer handle)
627 guint32 idx, segment;
628 gboolean destroy = FALSE;
631 _wapi_handle_segment (handle, &segment, &idx);
634 WapiHandleRequest req={0};
635 WapiHandleResponse resp={0};
637 req.type=WapiHandleRequestType_Close;
638 req.u.close.handle=GPOINTER_TO_UINT (handle);
640 _wapi_daemon_request_response (daemon_sock, &req, &resp);
641 if(resp.type!=WapiHandleResponseType_Close) {
642 g_warning (G_GNUC_PRETTY_FUNCTION
643 ": bogus daemon response, type %d",
645 g_assert_not_reached ();
647 destroy=resp.u.close.destroy;
650 _wapi_handle_get_shared_segment (segment)->handles[idx].ref--;
653 g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d", handle, _wapi_handle_get_shared_segment (segment)->handles[idx].ref);
656 /* Possible race condition here if another thread refs
657 * the handle between here and setting the type to
658 * UNUSED. I could lock a mutex, but I'm not sure
659 * that allowing a handle reference to reach 0 isn't
660 * an application bug anyway.
662 destroy=(_wapi_handle_get_shared_segment (segment)->handles[idx].ref==0);
667 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle %p",
672 _wapi_handle_ops_close_shared (handle);
674 memset (&_wapi_handle_get_shared_segment (segment)->handles[idx].u, '\0', sizeof(_wapi_handle_get_shared_segment (segment)->handles[idx].u));
677 _wapi_handle_ops_close_private (handle);
678 _wapi_handle_get_shared_segment (segment)->handles[idx].type=WAPI_HANDLE_UNUSED;
680 /* Destroy the mutex and cond var. We hope nobody
681 * tried to grab them between the handle unlock and
682 * now, but pthreads doesn't have a
683 * "unlock_and_destroy" atomic function.
685 thr_ret = mono_mutex_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
686 g_assert (thr_ret == 0);
688 thr_ret = pthread_cond_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond);
689 g_assert (thr_ret == 0);
693 #define HDRSIZE sizeof(struct _WapiScratchHeader)
695 static pthread_mutex_t _wapi_scratch_mutex=PTHREAD_MUTEX_INITIALIZER;
697 /* _wapi_scratch_mutex must be held when this function is called in
698 * the non-shared case
700 static void _wapi_handle_scratch_expand (void)
702 guint32 old_len, new_len;
704 old_len=sizeof(struct _WapiHandleScratch) +
705 _wapi_shared_scratch->data_len;
706 new_len=old_len+_WAPI_SHM_SCRATCH_SIZE;
708 if(_wapi_shared_scratch->is_shared==TRUE) {
709 /* expand via mmap() */
710 _wapi_shared_scratch=_wapi_shm_file_expand (_wapi_shared_scratch, WAPI_SHM_SCRATCH, 0, old_len, new_len);
712 _wapi_shared_scratch=_wapi_g_renew0 (_wapi_shared_scratch, old_len, new_len);
714 _wapi_shared_scratch->data_len+=_WAPI_SHM_SCRATCH_SIZE;
717 /* _wapi_scratch_mutex must be held when this function is called in
718 * the non-shared case
720 static guint32 _wapi_handle_scratch_locate_space (guint32 bytes)
722 guint32 idx=0, last_idx=0;
723 struct _WapiScratchHeader *hdr, *last_hdr = NULL;
724 gboolean last_was_free=FALSE;
725 guchar *storage=_wapi_shared_scratch->scratch_data;
728 g_message (G_GNUC_PRETTY_FUNCTION
729 ": looking for %d bytes of scratch space (%d bytes total)",
730 bytes, _wapi_shared_scratch->data_len);
733 while(idx< _wapi_shared_scratch->data_len) {
734 hdr=(struct _WapiScratchHeader *)&storage[idx];
736 /* Do a simple first-fit allocation, coalescing
737 * adjacent free blocks as we progress through the
740 if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
741 hdr->length >= bytes + HDRSIZE) {
743 guint32 old_length=hdr->length;
745 g_message (G_GNUC_PRETTY_FUNCTION ": found suitable free size at %d, length %d", idx, hdr->length);
748 hdr->flags &= ~WAPI_SHM_SCRATCH_FREE;
752 /* Put a new header in at the end of the used
755 hdr=(struct _WapiScratchHeader *)&storage[idx+bytes];
756 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
757 hdr->length = old_length-bytes-HDRSIZE;
760 g_message (G_GNUC_PRETTY_FUNCTION ": new header at %d, length %d", idx+bytes, hdr->length);
764 * It was memset(0..) when free/made so no need to do it here
768 } else if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
769 last_was_free == FALSE) {
771 g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous used)", idx, hdr->length);
774 /* save this point in case we can coalesce it with
775 * the next block, if that is free.
780 idx+=(hdr->length+HDRSIZE);
781 } else if (hdr->flags & WAPI_SHM_SCRATCH_FREE &&
782 last_was_free == TRUE) {
784 g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous free)", idx, hdr->length);
787 /* This block and the previous are both free,
790 last_hdr->length += (hdr->length + HDRSIZE);
792 /* If the new block is now big enough, use it
793 * (next time round the loop)
795 if(last_hdr->length >= bytes + HDRSIZE) {
798 /* leave the last free info as it is,
799 * in case the next block is also free
800 * and can be coalesced too
802 idx=last_idx+last_hdr->length+HDRSIZE;
806 g_message (G_GNUC_PRETTY_FUNCTION
807 ": found used block at %d, length %d", idx,
811 /* must be used, try next chunk */
812 idx+=(hdr->length+HDRSIZE);
814 /* Don't let the coalescing blow away this block */
817 /* But remember where the last block started */
822 /* Not enough free space. last_idx points to the last block.
823 * If it's free, just tack on more space and update the
824 * length. If it's allocated, it must have fit right into the
825 * available space, so add more space and add a new header
828 _wapi_handle_scratch_expand ();
829 storage=_wapi_shared_scratch->scratch_data;
831 hdr=(struct _WapiScratchHeader *)&storage[last_idx];
832 if(hdr->flags & WAPI_SHM_SCRATCH_FREE) {
833 hdr->length+=_WAPI_SHM_SCRATCH_SIZE;
835 idx=(hdr->length+HDRSIZE);
836 hdr=(struct _WapiScratchHeader *)&storage[idx];
837 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
838 hdr->length = _WAPI_SHM_SCRATCH_SIZE-HDRSIZE;
841 /* The caller will try again */
846 * _wapi_handle_scratch_store_internal:
847 * @bytes: Allocate no. bytes
849 * Like malloc(3) except its for the shared memory segment's scratch
850 * part. Memory block returned is zeroed out.
852 guint32 _wapi_handle_scratch_store_internal (guint32 bytes, gboolean *remap)
856 struct _WapiScratchHeader *hdr;
859 g_message (G_GNUC_PRETTY_FUNCTION ": storing %d bytes", bytes);
864 if(_wapi_shared_scratch->data_len==0) {
865 /* Need to expand the data array for the first use */
867 g_message (G_GNUC_PRETTY_FUNCTION
868 ": setting up scratch space");
871 _wapi_handle_scratch_expand ();
875 storage=_wapi_shared_scratch->scratch_data;
876 hdr=(struct _WapiScratchHeader *)&storage[0];
877 if(hdr->flags==0 && hdr->length==0) {
878 /* Need to initialise scratch data */
879 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
880 hdr->length = _wapi_shared_scratch->data_len - HDRSIZE;
883 idx=_wapi_handle_scratch_locate_space (bytes);
885 /* Some more space will have been allocated, so try again */
887 g_message (G_GNUC_PRETTY_FUNCTION ": trying again");
890 idx=_wapi_handle_scratch_locate_space (bytes);
897 guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes)
899 guint32 idx = 0, store_bytes;
905 g_message (G_GNUC_PRETTY_FUNCTION ": storing %d bytes", bytes);
908 /* No point storing no data */
913 /* Align bytes to 32 bits (needed for sparc at least) */
914 store_bytes = (((bytes) + 3) & (~3));
916 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
917 (void *)&_wapi_scratch_mutex);
918 thr_ret = pthread_mutex_lock (&_wapi_scratch_mutex);
919 g_assert (thr_ret == 0);
922 WapiHandleRequest scratch={0};
923 WapiHandleResponse scratch_resp={0};
924 guint32 old_len=sizeof(struct _WapiHandleScratch) +
925 _wapi_shared_scratch->data_len;
927 scratch.type=WapiHandleRequestType_Scratch;
928 scratch.u.scratch.length=store_bytes;
930 _wapi_daemon_request_response (daemon_sock, &scratch,
933 if(scratch_resp.type==WapiHandleResponseType_Scratch) {
934 idx=scratch_resp.u.scratch.idx;
935 remap=scratch_resp.u.scratch.remap;
937 g_warning (G_GNUC_PRETTY_FUNCTION
938 ": bogus daemon response, type %d",
940 g_assert_not_reached ();
944 munmap (_wapi_shared_scratch, old_len);
945 _wapi_shared_scratch=_wapi_shm_file_map (WAPI_SHM_SCRATCH, 0, NULL, NULL);
948 idx=_wapi_handle_scratch_store_internal (store_bytes, &remap);
950 /* Failed to allocate space */
957 g_message (G_GNUC_PRETTY_FUNCTION
958 ": stored [%s] at %d (len %d, aligned len %d)",
959 (char *)data, idx, bytes, store_bytes);
962 memcpy (&_wapi_shared_scratch->scratch_data[idx], data, bytes);
965 thr_ret = pthread_mutex_unlock (&_wapi_scratch_mutex);
966 g_assert (thr_ret == 0);
967 pthread_cleanup_pop (0);
972 guint32 _wapi_handle_scratch_store_string_array (gchar **data)
974 guint32 *stored_strings, count=0, i, idx;
977 /* No point storing no data */
983 while(*strings!=NULL) {
989 g_message (G_GNUC_PRETTY_FUNCTION ": %d strings to store", count);
996 /* stored_strings[0] is the count */
997 stored_strings=g_new0 (guint32, count+1);
998 stored_strings[0]=count;
1001 for(i=0; i<count; i++) {
1002 stored_strings[i+1]=_wapi_handle_scratch_store (strings[i], strlen (strings[i]));
1005 idx=_wapi_handle_scratch_store (stored_strings,
1006 sizeof(guint32)*(count+1));
1011 gpointer _wapi_handle_scratch_lookup (guint32 idx)
1013 struct _WapiScratchHeader *hdr;
1018 if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
1022 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
1023 (void *)&_wapi_scratch_mutex);
1024 thr_ret = pthread_mutex_lock (&_wapi_scratch_mutex);
1025 g_assert (thr_ret == 0);
1027 storage=_wapi_shared_scratch->scratch_data;
1029 hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
1030 ret=g_malloc0 (hdr->length+1);
1031 memcpy (ret, &storage[idx], hdr->length);
1033 thr_ret = pthread_mutex_unlock (&_wapi_scratch_mutex);
1034 g_assert (thr_ret == 0);
1035 pthread_cleanup_pop (0);
1040 gchar **_wapi_handle_scratch_lookup_string_array (guint32 idx)
1043 guint32 *stored_strings;
1046 if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
1050 stored_strings=_wapi_handle_scratch_lookup (idx);
1051 if(stored_strings==NULL) {
1055 /* stored_strings[0] is the number of strings, the index of
1056 * each string follows
1058 count=stored_strings[0];
1061 g_message (G_GNUC_PRETTY_FUNCTION
1062 ": looking up an array of %d strings", count);
1065 /* NULL-terminate the array */
1066 strings=g_new0 (gchar *, count+1);
1068 for(i=0; i<count; i++) {
1069 strings[i]=_wapi_handle_scratch_lookup (stored_strings[i+1]);
1072 g_message (G_GNUC_PRETTY_FUNCTION ": string %d is [%s]", i,
1077 g_free (stored_strings);
1083 * _wapi_handle_scratch_delete_internal:
1084 * @idx: Index to free block
1086 * Like free(3) except its for the shared memory segment's scratch
1089 void _wapi_handle_scratch_delete_internal (guint32 idx)
1091 struct _WapiScratchHeader *hdr;
1095 if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
1099 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
1100 (void *)&_wapi_scratch_mutex);
1101 thr_ret = pthread_mutex_lock (&_wapi_scratch_mutex);
1102 g_assert (thr_ret == 0);
1104 storage=_wapi_shared_scratch->scratch_data;
1106 hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
1107 memset (&storage[idx], '\0', hdr->length);
1108 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
1110 /* We could coalesce forwards here if the next block is also
1111 * free, but the _store() function will do that anyway.
1114 thr_ret = pthread_mutex_unlock (&_wapi_scratch_mutex);
1115 g_assert (thr_ret == 0);
1116 pthread_cleanup_pop (0);
1119 void _wapi_handle_scratch_delete (guint32 idx)
1122 WapiHandleRequest scratch_free={0};
1123 WapiHandleResponse scratch_free_resp={0};
1125 scratch_free.type=WapiHandleRequestType_ScratchFree;
1126 scratch_free.u.scratch_free.idx=idx;
1128 _wapi_daemon_request_response (daemon_sock, &scratch_free,
1129 &scratch_free_resp);
1131 if(scratch_free_resp.type!=WapiHandleResponseType_ScratchFree) {
1132 g_warning (G_GNUC_PRETTY_FUNCTION
1133 ": bogus daemon response, type %d",
1134 scratch_free_resp.type);
1135 g_assert_not_reached ();
1138 _wapi_handle_scratch_delete_internal (idx);
1142 void _wapi_handle_scratch_delete_string_array (guint32 idx)
1144 guint32 *stored_strings;
1147 stored_strings=_wapi_handle_scratch_lookup (idx);
1148 if(stored_strings==NULL) {
1152 /* stored_strings[0] is the number of strings, the index of
1153 * each string follows
1155 count=stored_strings[0];
1158 g_message (G_GNUC_PRETTY_FUNCTION ": deleting an array of %d strings",
1162 for(i=1; i<count; i++) {
1163 _wapi_handle_scratch_delete (stored_strings[i]);
1166 _wapi_handle_scratch_delete (idx);
1168 g_free (stored_strings);
1171 void _wapi_handle_register_capabilities (WapiHandleType type,
1172 WapiHandleCapability caps)
1174 handle_caps[type]=caps;
1177 gboolean _wapi_handle_test_capabilities (gpointer handle,
1178 WapiHandleCapability caps)
1180 guint32 idx, segment;
1181 WapiHandleType type;
1183 _wapi_handle_segment (handle, &segment, &idx);
1185 type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1188 g_message (G_GNUC_PRETTY_FUNCTION ": testing 0x%x against 0x%x (%d)",
1189 handle_caps[type], caps, handle_caps[type] & caps);
1192 return((handle_caps[type] & caps)!=0);
1195 void _wapi_handle_ops_close_shared (gpointer handle)
1197 guint32 idx, segment;
1198 WapiHandleType type;
1200 _wapi_handle_segment (handle, &segment, &idx);
1202 type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1204 if(handle_ops[type]!=NULL && handle_ops[type]->close_shared!=NULL) {
1205 handle_ops[type]->close_shared (handle);
1209 void _wapi_handle_ops_close_private (gpointer handle)
1211 guint32 idx, segment;
1212 WapiHandleType type;
1214 _wapi_handle_segment (handle, &segment, &idx);
1216 type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1218 /* When a handle in the process of being destroyed the shared
1219 * type has already been set to UNUSED
1221 if(type==WAPI_HANDLE_UNUSED && _wapi_private_data!=NULL) {
1222 type=_wapi_handle_get_private_segment (segment)->handles[idx].type;
1225 if(handle_ops[type]!=NULL && handle_ops[type]->close_private!=NULL) {
1226 handle_ops[type]->close_private (handle);
1230 void _wapi_handle_ops_signal (gpointer handle)
1232 guint32 idx, segment;
1233 WapiHandleType type;
1235 _wapi_handle_segment (handle, &segment, &idx);
1237 type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1239 if(handle_ops[type]!=NULL && handle_ops[type]->signal!=NULL) {
1240 handle_ops[type]->signal (handle);
1244 void _wapi_handle_ops_own (gpointer handle)
1246 guint32 idx, segment;
1247 WapiHandleType type;
1249 _wapi_handle_segment (handle, &segment, &idx);
1251 type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1253 if(handle_ops[type]!=NULL && handle_ops[type]->own_handle!=NULL) {
1254 handle_ops[type]->own_handle (handle);
1258 gboolean _wapi_handle_ops_isowned (gpointer handle)
1260 guint32 idx, segment;
1261 WapiHandleType type;
1263 _wapi_handle_segment (handle, &segment, &idx);
1265 type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1267 if(handle_ops[type]!=NULL && handle_ops[type]->is_owned!=NULL) {
1268 return(handle_ops[type]->is_owned (handle));
1276 * @handle: The handle to release
1278 * Closes and invalidates @handle, releasing any resources it
1279 * consumes. When the last handle to a temporary or non-persistent
1280 * object is closed, that object can be deleted. Closing the same
1281 * handle twice is an error.
1283 * Return value: %TRUE on success, %FALSE otherwise.
1285 gboolean CloseHandle(gpointer handle)
1287 _wapi_handle_unref (handle);
1292 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1298 guint32 count, i, iter=0;
1302 /* Lock all the handles, with backoff */
1304 for(i=0; i<numhandles; i++) {
1305 guint32 idx, segment;
1307 _wapi_handle_segment (handles[i], &segment, &idx);
1310 g_message (G_GNUC_PRETTY_FUNCTION ": attempting to lock %p",
1314 ret=mono_mutex_trylock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
1317 struct timespec sleepytime;
1320 g_message (G_GNUC_PRETTY_FUNCTION ": attempt failed for %p", handles[i]);
1324 _wapi_handle_segment (handles[i], &segment, &idx);
1325 thr_ret = mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
1326 g_assert (thr_ret == 0);
1329 /* If iter ever reaches 100 the nanosleep will
1330 * return EINVAL immediately, but we have a
1331 * design flaw if that happens.
1335 g_warning (G_GNUC_PRETTY_FUNCTION
1336 ": iteration overflow!");
1340 sleepytime.tv_sec=0;
1341 sleepytime.tv_nsec=10000000 * iter; /* 10ms*iter */
1344 g_message (G_GNUC_PRETTY_FUNCTION
1345 ": Backing off for %d ms", iter*10);
1347 nanosleep (&sleepytime, NULL);
1354 g_message (G_GNUC_PRETTY_FUNCTION ": Locked all handles");
1360 for(i=0; i<numhandles; i++) {
1361 guint32 idx, segment;
1363 _wapi_handle_ref (handles[i]);
1365 _wapi_handle_segment (handles[i], &segment, &idx);
1368 g_message (G_GNUC_PRETTY_FUNCTION ": Checking handle %p",
1372 if(((_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_OWN)==TRUE) &&
1373 (_wapi_handle_ops_isowned (handles[i])==TRUE)) ||
1374 (_wapi_handle_get_shared_segment (segment)->handles[idx].signalled==TRUE)) {
1378 g_message (G_GNUC_PRETTY_FUNCTION
1379 ": Handle %p signalled", handles[i]);
1388 g_message (G_GNUC_PRETTY_FUNCTION ": %d event handles signalled",
1392 if((waitall==TRUE && count==numhandles) ||
1393 (waitall==FALSE && count>0)) {
1400 g_message (G_GNUC_PRETTY_FUNCTION ": Returning %d", ret);
1408 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1413 for(i=0; i<numhandles; i++) {
1414 guint32 idx, segment;
1416 _wapi_handle_segment (handles[i], &segment, &idx);
1419 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p",
1423 thr_ret = mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
1424 g_assert (thr_ret == 0);
1426 _wapi_handle_unref (handles[i]);
1430 /* Process-shared handles (currently only process and thread handles
1431 * are allowed, and they only work because once signalled they can't
1432 * become unsignalled) are waited for by one process and signalled by
1433 * another. Without process-shared conditions, the waiting process
1434 * will block forever. To get around this, the four handle waiting
1435 * functions use a short timeout when _POSIX_THREAD_PROCESS_SHARED is
1436 * not available. They also return "success" if the fake timeout
1437 * expired, and let the caller check signal status.
1439 int _wapi_handle_wait_signal (void)
1441 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1442 return(mono_cond_wait (&_wapi_handle_get_shared_segment (0)->signal_cond,
1443 &_wapi_handle_get_shared_segment (0)->signal_mutex));
1445 struct timespec fake_timeout;
1448 _wapi_calc_timeout (&fake_timeout, 100);
1450 ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
1451 &_wapi_handle_get_private_segment (0)->signal_mutex,
1453 if(ret==ETIMEDOUT) {
1458 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1461 int _wapi_handle_timedwait_signal (struct timespec *timeout)
1463 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1464 return(mono_cond_timedwait (&_wapi_handle_get_shared_segment (0)->signal_cond,
1465 &_wapi_handle_get_shared_segment (0)->signal_mutex,
1468 struct timespec fake_timeout;
1471 _wapi_calc_timeout (&fake_timeout, 100);
1473 if((fake_timeout.tv_sec>timeout->tv_sec) ||
1474 (fake_timeout.tv_sec==timeout->tv_sec &&
1475 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1476 /* Real timeout is less than 100ms time */
1477 ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
1478 &_wapi_handle_get_private_segment (0)->signal_mutex,
1481 ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
1482 &_wapi_handle_get_private_segment (0)->signal_mutex,
1484 if(ret==ETIMEDOUT) {
1490 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1493 int _wapi_handle_wait_signal_handle (gpointer handle)
1495 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1496 guint32 idx, segment;
1498 _wapi_handle_segment (handle, &segment, &idx);
1500 return(mono_cond_wait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1501 &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex));
1503 guint32 idx, segment;
1504 struct timespec fake_timeout;
1507 _wapi_handle_segment (handle, &segment, &idx);
1508 _wapi_calc_timeout (&fake_timeout, 100);
1510 ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1511 &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1513 if(ret==ETIMEDOUT) {
1518 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1521 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1522 struct timespec *timeout)
1524 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1525 guint32 idx, segment;
1527 _wapi_handle_segment (handle, &segment, &idx);
1529 return(mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1530 &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1533 guint32 idx, segment;
1534 struct timespec fake_timeout;
1537 _wapi_handle_segment (handle, &segment, &idx);
1538 _wapi_calc_timeout (&fake_timeout, 100);
1540 if((fake_timeout.tv_sec>timeout->tv_sec) ||
1541 (fake_timeout.tv_sec==timeout->tv_sec &&
1542 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1543 /* Real timeout is less than 100ms time */
1544 ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1545 &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1548 ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1549 &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1551 if(ret==ETIMEDOUT) {
1557 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1560 gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
1561 gboolean inherit, guint32 flags,
1562 gpointer stdin_handle,
1563 gpointer stdout_handle,
1564 gpointer stderr_handle,
1565 gpointer *process_handle,
1566 gpointer *thread_handle, guint32 *pid,
1569 WapiHandleRequest fork_proc={0};
1570 WapiHandleResponse fork_proc_resp={0};
1571 int in_fd, out_fd, err_fd;
1577 fork_proc.type=WapiHandleRequestType_ProcessFork;
1578 fork_proc.u.process_fork.cmd=cmd;
1579 fork_proc.u.process_fork.env=env;
1580 fork_proc.u.process_fork.dir=dir;
1581 fork_proc.u.process_fork.stdin_handle=GPOINTER_TO_UINT (stdin_handle);
1582 fork_proc.u.process_fork.stdout_handle=GPOINTER_TO_UINT (stdout_handle);
1583 fork_proc.u.process_fork.stderr_handle=GPOINTER_TO_UINT (stderr_handle);
1584 fork_proc.u.process_fork.inherit=inherit;
1585 fork_proc.u.process_fork.flags=flags;
1587 in_fd=_wapi_file_handle_to_fd (stdin_handle);
1588 out_fd=_wapi_file_handle_to_fd (stdout_handle);
1589 err_fd=_wapi_file_handle_to_fd (stderr_handle);
1591 if(in_fd==-1 || out_fd==-1 || err_fd==-1) {
1592 /* We were given duff handles */
1593 /* FIXME: error code */
1597 _wapi_daemon_request_response_with_fds (daemon_sock, &fork_proc,
1598 &fork_proc_resp, in_fd,
1600 if(fork_proc_resp.type==WapiHandleResponseType_ProcessFork) {
1601 *process_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.process_handle);
1602 *thread_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.thread_handle);
1603 *pid=fork_proc_resp.u.process_fork.pid;
1604 *tid=fork_proc_resp.u.process_fork.tid;
1606 /* If there was an internal error, the handles will be
1607 * 0. If there was an error forking or execing, the
1608 * handles will have values, and process_handle's
1609 * exec_errno will be set, and the handle will be
1610 * signalled immediately.
1612 if(process_handle==0 || thread_handle==0) {
1618 g_warning (G_GNUC_PRETTY_FUNCTION
1619 ": bogus daemon response, type %d",
1620 fork_proc_resp.type);
1621 g_assert_not_reached ();
1628 _wapi_handle_process_kill (pid_t process, guint32 signo, gint *errnum)
1630 WapiHandleRequest killproc = {0};
1631 WapiHandleResponse killprocresp = {0};
1634 if (shared != TRUE) {
1635 if (errnum) *errnum = EINVAL;
1639 killproc.type = WapiHandleRequestType_ProcessKill;
1640 killproc.u.process_kill.pid = process;
1641 killproc.u.process_kill.signo = signo;
1643 _wapi_daemon_request_response (daemon_sock, &killproc, &killprocresp);
1645 if (killprocresp.type != WapiHandleResponseType_ProcessKill) {
1646 g_warning (G_GNUC_PRETTY_FUNCTION
1647 ": bogus daemon response, type %d",
1649 g_assert_not_reached ();
1652 result = killprocresp.u.process_kill.err;
1653 if (result != 0 && errnum != NULL)
1654 *errnum = (result == FALSE) ? result : 0;
1656 return (result == 0);
1659 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1660 guint32 new_sharemode,
1662 guint32 *old_sharemode,
1663 guint32 *old_access)
1665 WapiHandleRequest req = {0};
1666 WapiHandleResponse resp = {0};
1668 if(shared != TRUE) {
1669 /* No daemon means we don't know if a file is sharable.
1670 * We're running in our own little world if this is
1671 * the case, so there's no point in pretending that
1672 * the file isn't sharable.
1677 req.type = WapiHandleRequestType_GetOrSetShare;
1678 req.u.get_or_set_share.device = device;
1679 req.u.get_or_set_share.inode = inode;
1680 req.u.get_or_set_share.new_sharemode = new_sharemode;
1681 req.u.get_or_set_share.new_access = new_access;
1683 _wapi_daemon_request_response (daemon_sock, &req, &resp);
1684 if (resp.type != WapiHandleResponseType_GetOrSetShare) {
1685 g_warning (G_GNUC_PRETTY_FUNCTION
1686 ": bogus daemon response, type %d", resp.type);
1687 g_assert_not_reached ();
1690 *old_sharemode = resp.u.get_or_set_share.sharemode;
1691 *old_access = resp.u.get_or_set_share.access;
1693 return(resp.u.get_or_set_share.exists);
1696 void _wapi_handle_set_share (dev_t device, ino_t inode, guint32 sharemode,
1699 WapiHandleRequest req = {0};
1700 WapiHandleResponse resp = {0};
1702 if(shared != TRUE) {
1703 /* No daemon, so there's no one else to tell about
1709 req.type = WapiHandleRequestType_SetShare;
1710 req.u.set_share.device = device;
1711 req.u.set_share.inode = inode;
1712 req.u.set_share.sharemode = sharemode;
1713 req.u.set_share.access = access;
1715 _wapi_daemon_request_response (daemon_sock, &req, &resp);
1716 if (resp.type != WapiHandleResponseType_SetShare) {
1717 g_warning (G_GNUC_PRETTY_FUNCTION
1718 ": bogus daemon response, type %d", resp.type);
1719 g_assert_not_reached ();