2 * daemon.c: The handle daemon
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
14 #include <sys/types.h>
15 #include <sys/socket.h>
25 #include <mono/io-layer/io-layer.h>
26 #include <mono/io-layer/handles-private.h>
27 #include <mono/io-layer/wapi-private.h>
28 #include <mono/io-layer/daemon-messages.h>
29 #include <mono/io-layer/timefuncs-private.h>
30 #include <mono/io-layer/daemon-private.h>
34 /* The shared thread codepath doesn't seem to work yet... */
35 #undef _POSIX_THREAD_PROCESS_SHARED
37 /* Keep track of the number of clients */
39 /* Arrays to keep track of handles that have been referenced by the
40 * daemon and clients. client_handles is indexed by file descriptor
43 static guint32 *daemon_handles=NULL, **client_handles=NULL;
44 static int client_handles_length=0;
46 /* The socket which we listen to new connections on */
49 /* Set to TRUE by the SIGCHLD signal handler */
50 static volatile gboolean check_processes=FALSE;
52 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
56 /* Deletes the shared memory segment. If we're exiting on error,
57 * clients will get EPIPEs.
59 static void cleanup (void)
63 #ifdef NEED_LINK_UNLINK
64 unlink(_wapi_shared_data[0]->daemon);
66 for(i=1; i<_wapi_shared_data[0]->num_segments; i++) {
67 unlink (_wapi_shm_file (WAPI_SHM_DATA, i));
69 unlink (_wapi_shm_file (WAPI_SHM_DATA, 0));
71 /* There's only one scratch file */
72 unlink (_wapi_shm_file (WAPI_SHM_SCRATCH, 0));
75 /* If there is only one socket, and no child processes, we can exit.
76 * We test for child processes by counting handle references held by
79 static void maybe_exit (void)
84 g_message (G_GNUC_PRETTY_FUNCTION ": Seeing if we should exit");
89 g_message (G_GNUC_PRETTY_FUNCTION ": Still got clients");
95 i<_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT;
97 if(daemon_handles[i]>0) {
99 g_message (G_GNUC_PRETTY_FUNCTION
100 ": Still got handle references");
107 g_message (G_GNUC_PRETTY_FUNCTION ": Byebye");
118 * Called if daemon receives a SIGTERM or SIGINT
120 static void signal_handler (int unused)
130 * Called if daemon receives a SIGCHLD, and notes that a process needs
131 * to be wait()ed for.
133 static void sigchld_handler (int unused)
135 /* Notice that a child process died */
136 check_processes=TRUE;
142 * Bind signals and attach to shared memory
144 static void startup (void)
148 sa.sa_handler=signal_handler;
149 sigemptyset (&sa.sa_mask);
151 sigaction (SIGINT, &sa, NULL);
152 sigaction (SIGTERM, &sa, NULL);
154 #ifndef HAVE_MSG_NOSIGNAL
155 sa.sa_handler=SIG_IGN;
156 sigaction (SIGPIPE, &sa, NULL);
159 sa.sa_handler=sigchld_handler;
160 sa.sa_flags=SA_NOCLDSTOP;
161 sigaction (SIGCHLD, &sa, NULL);
163 #ifdef NEED_LINK_UNLINK
164 /* Here's a more portable method... */
165 snprintf (_wapi_shared_data[0]->daemon, MONO_SIZEOF_SUNPATH-1,
166 "/tmp/mono-handle-daemon-%d-%ld-%ld", getuid (), random (),
169 /* Leave the first byte NULL so we create the socket in the
170 * abstrace namespace, not on the filesystem. (Lets see how
171 * portable _that_ is :)
173 * The name is intended to be unique, not cryptographically
176 snprintf (_wapi_shared_data[0]->daemon+1, MONO_SIZEOF_SUNPATH-2,
177 "mono-handle-daemon-%d-%d-%ld", getuid (), getpid (),
185 * @open_handles: An array of handles referenced by the calling client
186 * @handle: handle to inc refcnt
188 * Increase ref count of handle for the calling client. Handle 0 is
191 static void ref_handle (guint32 *open_handles, guint32 handle)
193 guint32 segment, idx;
199 _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
201 _wapi_shared_data[segment]->handles[idx].ref++;
202 open_handles[handle]++;
205 g_message (G_GNUC_PRETTY_FUNCTION
206 ": handle 0x%x ref now %d (%d this process)", handle,
207 _wapi_shared_data[segment]->handles[idx].ref,
208 open_handles[handle]);
214 * @open_handles: An array of handles referenced by the calling client
215 * @handle: handle to inc refcnt
217 * Decrease ref count of handle for the calling client. If global ref
218 * count reaches 0 it is free'ed. Return TRUE if the local ref count
219 * is 0. Handle 0 is ignored.
221 static gboolean unref_handle (guint32 *open_handles, guint32 handle)
223 gboolean destroy=FALSE;
224 guint32 segment, idx;
230 if (open_handles[handle] == 0) {
231 g_warning(G_GNUC_PRETTY_FUNCTION
232 ": unref on %d called when ref was already 0",
237 _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
239 _wapi_shared_data[segment]->handles[idx].ref--;
240 open_handles[handle]--;
243 g_message (G_GNUC_PRETTY_FUNCTION
244 ": handle 0x%x ref now %d (%d this process)", handle,
245 _wapi_shared_data[segment]->handles[idx].ref,
246 open_handles[handle]);
249 if(open_handles[handle]==0) {
250 /* This client has released the handle */
254 if(_wapi_shared_data[segment]->handles[idx].ref==0) {
255 if (open_handles[handle]!=0) {
256 g_warning (G_GNUC_PRETTY_FUNCTION ": per-process open_handles mismatch, set to %d, should be 0", open_handles[handle]);
260 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle 0x%x",
264 _wapi_handle_ops_close_shared (GUINT_TO_POINTER (handle));
266 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
267 mono_mutex_destroy (&_wapi_shared_data[segment]->handles[idx].signal_mutex);
268 pthread_cond_destroy (&_wapi_shared_data[segment]->handles[idx].signal_cond);
271 memset (&_wapi_shared_data[segment]->handles[idx].u, '\0', sizeof(_wapi_shared_data[segment]->handles[idx].u));
272 _wapi_shared_data[segment]->handles[idx].type=WAPI_HANDLE_UNUSED;
275 if(open_handles==daemon_handles) {
276 /* The daemon released a reference, so see if it's
287 * @fd: Filehandle to add
289 * Create a new GIOChannel, and add it to the main loop event sources.
291 static void add_fd(int fd)
293 GIOChannel *io_channel;
296 io_channel=g_io_channel_unix_new (fd);
298 /* Turn off all encoding and buffering crap */
299 g_io_channel_set_encoding (io_channel, NULL, NULL);
300 g_io_channel_set_buffered (io_channel, FALSE);
302 refs=g_new0 (guint32,_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
303 if(daemon_handles==NULL) {
304 /* We rely on the daemon channel being created first.
305 * That's safe, because every other channel is the
306 * result of an accept() on the daemon channel.
311 if(fd>=client_handles_length) {
312 /* Add a bit of padding, so we dont resize for _every_
315 int old_len=client_handles_length * sizeof(guint32 *);
317 client_handles_length=fd+10;
318 if(client_handles==NULL) {
319 client_handles=g_new0 (guint32 *,
320 client_handles_length);
322 /* Can't use g_renew here, because the unused
323 * elements must be NULL and g_renew doesn't
324 * initialise the memory it returns
326 client_handles=_wapi_g_renew0 (client_handles, old_len, client_handles_length * sizeof(guint32 *));
329 client_handles[fd]=refs;
331 g_io_add_watch (io_channel, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
339 * @channel: GIOChannel to close
341 * Closes the IO channel. Closes all handles that it may have open. If
342 * only main_sock is left, the daemon is shut down.
344 static void rem_fd(GIOChannel *channel, guint32 *open_handles)
346 guint32 handle_count;
349 fd=g_io_channel_unix_get_fd (channel);
351 if(fd == main_sock) {
352 /* We shouldn't be deleting the daemon's fd */
353 g_warning (G_GNUC_PRETTY_FUNCTION ": Deleting daemon fd!");
359 g_message (G_GNUC_PRETTY_FUNCTION ": Removing client fd %d", fd);
362 g_io_channel_shutdown (channel, TRUE, NULL);
365 i<_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT;
367 handle_count=open_handles[i];
369 for(j=0; j<handle_count; j++) {
371 g_message (G_GNUC_PRETTY_FUNCTION ": closing handle 0x%x for client at index %d", i, g_io_channel_unix_get_fd (channel));
373 /* Ignore the hint to the client to destroy
374 * the handle private data
376 unref_handle (open_handles, i);
380 g_free (open_handles);
381 client_handles[fd]=NULL;
385 /* Just the master socket left, so see if we can
392 static gboolean process_compare (gpointer handle, gpointer user_data)
394 struct _WapiHandle_process *process_handle;
398 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
399 (gpointer *)&process_handle, NULL);
401 g_warning (G_GNUC_PRETTY_FUNCTION
402 ": error looking up process handle %p", handle);
406 pid=GPOINTER_TO_UINT (user_data);
407 if(process_handle->id==pid) {
414 static gboolean process_thread_compare (gpointer handle, gpointer user_data)
416 struct _WapiHandle_thread *thread_handle;
418 guint32 segment, idx;
420 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
421 (gpointer *)&thread_handle, NULL);
423 g_warning (G_GNUC_PRETTY_FUNCTION
424 ": error looking up thread handle %p", handle);
428 if(thread_handle->process_handle==user_data) {
429 /* Signal the handle. Don't use
430 * _wapi_handle_set_signal_state() unless we have
431 * process-shared pthread support.
434 g_message (G_GNUC_PRETTY_FUNCTION ": Set thread handle %p signalled, because its process died", handle);
437 thread_handle->exitstatus=0;
439 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
440 _wapi_handle_lock_handle (handle);
441 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
442 _wapi_handle_unlock_handle (handle);
444 /* Just tweak the signal state directly. This is not
445 * recommended behaviour, but it works for threads
446 * because they can never become unsignalled. There
447 * are some nasty kludges in the handle waiting code
448 * to cope with missing condition signals for when
449 * process-shared pthread support is missing.
451 _wapi_handle_segment (handle, &segment, &idx);
452 _wapi_shared_data[segment]->handles[idx].signalled=TRUE;
453 #endif /* _POSIX_THREAD_PROCESS_SHARED */
456 /* Return false to keep searching */
460 /* Find the handle associated with pid, mark it dead and record exit
461 * status. Finds all thread handles associated with this process
462 * handle, and marks those signalled too, with exitstatus '0'. It
463 * also drops the daemon's reference to the handle, and the thread
464 * pointed at by main_thread.
466 static void process_post_mortem (pid_t pid, int status)
468 gpointer process_handle;
469 struct _WapiHandle_process *process_handle_data;
470 guint32 segment, idx;
472 process_handle=_wapi_search_handle (WAPI_HANDLE_PROCESS,
474 GUINT_TO_POINTER (pid),
475 (gpointer *)&process_handle_data,
477 if(process_handle==0) {
478 g_warning (G_GNUC_PRETTY_FUNCTION
479 ": Couldn't find handle for process %d!", pid);
481 /* Signal the handle. Don't use
482 * _wapi_handle_set_signal_state() unless we have
483 * process-shared pthread support.
488 g_message (G_GNUC_PRETTY_FUNCTION
489 ": Set process %d exitstatus to %d", pid,
490 WEXITSTATUS (status));
493 /* Technically WEXITSTATUS is only valid if the
494 * process exited normally, but I don't care if the
495 * process caught a signal or not.
497 process_handle_data->exitstatus=WEXITSTATUS (status);
500 gettimeofday (&tv, NULL);
501 _wapi_timeval_to_filetime (&tv,
502 &process_handle_data->exit_time);
504 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
505 _wapi_handle_lock_handle (process_handle);
506 _wapi_handle_set_signal_state (process_handle, TRUE, TRUE);
507 _wapi_handle_unlock_handle (process_handle);
509 /* Just tweak the signal state directly. This is not
510 * recommended behaviour, but it works for processes
511 * because they can never become unsignalled. There
512 * are some nasty kludges in the handle waiting code
513 * to cope with missing condition signals for when
514 * process-shared pthread support is missing.
516 _wapi_handle_segment (process_handle, &segment, &idx);
517 _wapi_shared_data[segment]->handles[idx].signalled=TRUE;
518 #endif /* _POSIX_THREAD_PROCESS_SHARED */
521 /* Find all threads that have their process
522 * handle==process_handle. Ignore the return value, all the
523 * work will be done in the compare func
525 (void)_wapi_search_handle (WAPI_HANDLE_THREAD, process_thread_compare,
526 process_handle, NULL, NULL);
528 unref_handle (daemon_handles,
529 GPOINTER_TO_UINT (process_handle_data->main_thread));
530 unref_handle (daemon_handles, GPOINTER_TO_UINT (process_handle));
533 static void process_died (void)
538 check_processes=FALSE;
541 g_message (G_GNUC_PRETTY_FUNCTION ": Reaping processes");
545 pid=waitpid (-1, &status, WNOHANG);
546 if(pid==0 || pid==-1) {
547 /* Finished waiting. I was checking pid==-1
548 * separately but was getting ECHILD when
549 * there were no more child processes (which
550 * doesnt seem to conform to the man page)
554 /* pid contains the ID of a dead process */
556 g_message (G_GNUC_PRETTY_FUNCTION ": process %d reaped", pid);
558 process_post_mortem (pid, status);
566 * @channel: channel to send reply to
567 * @resp: Package to send
569 * Send a package to a client
571 static void send_reply (GIOChannel *channel, WapiHandleResponse *resp)
574 _wapi_daemon_response (g_io_channel_unix_get_fd (channel), resp);
579 * @channel: The client making the request
580 * @open_handles: An array of handles referenced by this client
581 * @type: type to init handle to
583 * Find a free handle and initialize it to 'type', increase refcnt and
584 * send back a reply to the client.
586 static void process_new (GIOChannel *channel, guint32 *open_handles,
590 WapiHandleResponse resp={0};
592 handle=_wapi_handle_new_internal (type);
594 /* Try and allocate a new shared segment, and have
597 guint32 segment=_wapi_shared_data[0]->num_segments;
600 _wapi_handle_ensure_mapped (segment);
601 if(_wapi_shared_data[segment]!=NULL) {
602 /* Got a new segment */
603 gulong old_len, new_len;
605 old_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
606 _wapi_shared_data[0]->num_segments++;
607 new_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
609 /* Need to expand all the handle reference
613 for(i=0; i<client_handles_length; i++) {
614 if(client_handles[i]!=NULL) {
615 client_handles[i]=_wapi_g_renew0 (client_handles[i], old_len, new_len);
619 /* And find the new location for open_handles... */
620 i=g_io_channel_unix_get_fd (channel);
621 open_handles=client_handles[i];
622 daemon_handles=client_handles[main_sock];
624 handle=_wapi_handle_new_internal (type);
626 /* Map failed. Just return 0 meaning "out of
632 /* handle might still be set to 0. This is handled at the
636 ref_handle (open_handles, handle);
639 g_message (G_GNUC_PRETTY_FUNCTION ": returning new handle 0x%x",
643 resp.type=WapiHandleResponseType_New;
644 resp.u.new.type=type;
645 resp.u.new.handle=handle;
647 send_reply (channel, &resp);
652 * @channel: The client making the request
653 * @open_handles: An array of handles referenced by this client
654 * @handle: handle no.
656 * Increase refcnt on a previously created handle and send back a
657 * response to the client.
659 static void process_open (GIOChannel *channel, guint32 *open_handles,
662 WapiHandleResponse resp={0};
663 guint32 segment, idx;
664 struct _WapiHandleShared *shared;
666 _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
667 shared=&_wapi_shared_data[segment]->handles[idx];
669 if(shared->type!=WAPI_HANDLE_UNUSED && handle!=0) {
670 ref_handle (open_handles, handle);
673 g_message (G_GNUC_PRETTY_FUNCTION
674 ": returning new handle 0x%x", handle);
677 resp.type=WapiHandleResponseType_Open;
678 resp.u.new.type=shared->type;
679 resp.u.new.handle=handle;
681 send_reply (channel, &resp);
686 resp.type=WapiHandleResponseType_Open;
689 send_reply (channel, &resp);
694 * @channel: The client making the request
695 * @open_handles: An array of handles referenced by this client
696 * @handle: handle no.
698 * Decrease refcnt on a previously created handle and send back a
699 * response to the client with notice of it being destroyed.
701 static void process_close (GIOChannel *channel, guint32 *open_handles,
704 WapiHandleResponse resp={0};
706 resp.type=WapiHandleResponseType_Close;
707 resp.u.close.destroy=unref_handle (open_handles, handle);
710 g_message (G_GNUC_PRETTY_FUNCTION ": unreffing handle 0x%x", handle);
713 send_reply (channel, &resp);
718 * @channel: The client making the request
719 * @length: allocate this much scratch space
721 * Allocate some scratch space and send a reply to the client.
723 static void process_scratch (GIOChannel *channel, guint32 length)
725 WapiHandleResponse resp={0};
727 resp.type=WapiHandleResponseType_Scratch;
728 resp.u.scratch.idx=_wapi_handle_scratch_store_internal (length, &resp.u.scratch.remap);
730 g_message (G_GNUC_PRETTY_FUNCTION ": allocating scratch index 0x%x",
734 send_reply (channel, &resp);
738 * process_scratch_free:
739 * @channel: The client making the request
740 * @scratch_idx: deallocate this scratch space
742 * Deallocate scratch space and send a reply to the client.
744 static void process_scratch_free (GIOChannel *channel, guint32 scratch_idx)
746 WapiHandleResponse resp={0};
748 resp.type=WapiHandleResponseType_ScratchFree;
749 _wapi_handle_scratch_delete_internal (scratch_idx);
752 g_message (G_GNUC_PRETTY_FUNCTION ": deleting scratch index 0x%x",
756 send_reply (channel, &resp);
760 * process_process_fork:
761 * @channel: The client making the request
762 * @open_handles: An array of handles referenced by this client
763 * @process_fork: Describes the process to fork
764 * @fds: stdin, stdout, and stderr for the new process
766 * Forks a new process, and returns the process and thread data to the
769 static void process_process_fork (GIOChannel *channel, guint32 *open_handles,
770 WapiHandleRequest_ProcessFork process_fork,
773 WapiHandleResponse resp={0};
774 guint32 process_handle, thread_handle;
775 struct _WapiHandle_process *process_handle_data;
776 struct _WapiHandle_thread *thread_handle_data;
779 resp.type=WapiHandleResponseType_ProcessFork;
781 /* Create handles first, so the child process can store exec
782 * errors. Either handle might be set to 0, if this happens
783 * just reply to the client without bothering to fork. The
784 * client must check if either handle is 0 and take
785 * appropriate error handling action.
787 process_handle=_wapi_handle_new_internal (WAPI_HANDLE_PROCESS);
788 ref_handle (daemon_handles, process_handle);
789 ref_handle (open_handles, process_handle);
791 thread_handle=_wapi_handle_new_internal (WAPI_HANDLE_THREAD);
792 ref_handle (daemon_handles, thread_handle);
793 ref_handle (open_handles, thread_handle);
795 if(process_handle==0 || thread_handle==0) {
796 /* unref_handle() copes with the handle being 0 */
797 unref_handle (daemon_handles, process_handle);
798 unref_handle (open_handles, process_handle);
799 unref_handle (daemon_handles, thread_handle);
800 unref_handle (open_handles, thread_handle);
804 char *cmd=NULL, *dir=NULL, **argv, **env;
809 /* Get usable copies of the cmd, dir and env now
810 * rather than in the child process. This is to
811 * prevent the race condition where the parent can
812 * return the reply to the client, which then promptly
813 * deletes the scratch data before the new process
814 * gets to see it. Also explode argv here so we can
815 * use it to set the process name.
817 cmd=_wapi_handle_scratch_lookup (process_fork.cmd);
818 dir=_wapi_handle_scratch_lookup (process_fork.dir);
819 env=_wapi_handle_scratch_lookup_string_array (process_fork.env);
821 ret=g_shell_parse_argv (cmd, NULL, &argv, &gerr);
823 /* FIXME: Could do something with the
826 process_handle_data->exec_errno=gerr->code;
829 g_message (G_GNUC_PRETTY_FUNCTION ": forking");
832 _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
834 (gpointer *)&process_handle_data,
837 _wapi_lookup_handle (GUINT_TO_POINTER (thread_handle),
839 (gpointer *)&thread_handle_data,
842 /* Fork, exec cmd with args and optional env,
843 * and return the handles with pid and blank
848 process_handle_data->exec_errno=errno;
853 /* should we detach from the process
854 * group? We're already running
855 * without a controlling tty...
858 /* Connect stdin, stdout and stderr */
863 if(process_fork.inherit!=TRUE) {
864 /* FIXME: do something here */
867 /* Close all file descriptors */
868 for(i=3; i<getdtablesize (); i++) {
872 /* pass process and thread handle info
873 * to the child, so it doesn't have to
874 * do an expensive search over the
880 while(env[env_count]!=NULL) {
884 env=(char **)g_renew (char **, env, env_count+2);
886 env[env_count]=g_strdup_printf ("_WAPI_PROCESS_HANDLE=%d", process_handle);
887 env[env_count+1]=g_strdup_printf ("_WAPI_THREAD_HANDLE=%d", process_handle);
888 env[env_count+2]=NULL;
892 g_message (G_GNUC_PRETTY_FUNCTION
893 ": exec()ing [%s] in dir [%s]",
897 while(argv[i]!=NULL) {
898 g_message ("arg %d: [%s]",
904 while(env[i]!=NULL) {
905 g_message ("env %d: [%s]",
913 if(chdir (dir)==-1) {
914 process_handle_data->exec_errno=errno;
919 execve (argv[0], argv, env);
922 process_handle_data->exec_errno=errno;
928 /* store process name, based on the last section of the cmd */
930 char *slash=strrchr (argv[0], '/');
933 process_handle_data->proc_name=_wapi_handle_scratch_store (slash+1, strlen (slash+1));
935 process_handle_data->proc_name=_wapi_handle_scratch_store (argv[0], strlen (argv[0]));
939 /* These seem to be the defaults on w2k */
940 process_handle_data->min_working_set=204800;
941 process_handle_data->max_working_set=1413120;
953 process_handle_data->id=pid;
954 process_handle_data->main_thread=GUINT_TO_POINTER (thread_handle);
956 gettimeofday (&tv, NULL);
957 _wapi_timeval_to_filetime (&tv,
958 &process_handle_data->create_time);
960 /* FIXME: if env==0, inherit the env from the current
963 process_handle_data->env=process_fork.env;
965 thread_handle_data->process_handle=GUINT_TO_POINTER (process_handle);
967 resp.u.process_fork.pid=pid;
970 resp.u.process_fork.process_handle=process_handle;
971 resp.u.process_fork.thread_handle=thread_handle;
973 send_reply (channel, &resp);
978 * @channel: The client to read the request from
979 * @open_handles: An array of handles referenced by this client
981 * Read a message (A WapiHandleRequest) from a client and dispatch
982 * whatever it wants to the process_* calls.
984 static void read_message (GIOChannel *channel, guint32 *open_handles)
986 WapiHandleRequest req;
987 int fds[3]={0, 1, 2};
989 gboolean has_fds=FALSE;
992 ret=_wapi_daemon_request (g_io_channel_unix_get_fd (channel), &req,
995 /* Other end went away */
997 g_message ("Read 0 bytes on fd %d, closing it",
998 g_io_channel_unix_get_fd (channel));
1001 rem_fd (channel, open_handles);
1006 case WapiHandleRequestType_New:
1007 process_new (channel, open_handles, req.u.new.type);
1009 case WapiHandleRequestType_Open:
1011 g_assert(req.u.open.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1013 process_open (channel, open_handles, req.u.open.handle);
1015 case WapiHandleRequestType_Close:
1017 g_assert(req.u.close.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1019 process_close (channel, open_handles, req.u.close.handle);
1021 case WapiHandleRequestType_Scratch:
1022 process_scratch (channel, req.u.scratch.length);
1024 case WapiHandleRequestType_ScratchFree:
1025 process_scratch_free (channel, req.u.scratch_free.idx);
1027 case WapiHandleRequestType_ProcessFork:
1028 process_process_fork (channel, open_handles,
1029 req.u.process_fork, fds);
1031 case WapiHandleRequestType_Error:
1034 /* Catch bogus requests */
1035 /* FIXME: call rem_fd? */
1041 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[0]);
1042 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[1]);
1043 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[2]);
1054 * @channel: The IO channel that is active
1055 * @condition: The condition that has been satisfied
1056 * @data: A pointer to an array of handles referenced by this client
1058 * The callback called by the main loop when there is activity on an
1061 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
1064 int fd=g_io_channel_unix_get_fd (channel);
1065 guint32 *open_handles=client_handles[fd];
1067 if(condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
1069 g_message ("fd %d error", fd);
1072 rem_fd (channel, open_handles);
1076 if(condition & (G_IO_IN | G_IO_PRI)) {
1079 struct sockaddr addr;
1080 socklen_t addrlen=sizeof(struct sockaddr);
1082 newsock=accept (main_sock, &addr, &addrlen);
1084 g_critical ("accept error: %s",
1085 g_strerror (errno));
1091 g_message ("accept returning %d", newsock);
1097 g_message ("reading data on fd %d", fd);
1100 read_message (channel, open_handles);
1105 return(FALSE); /* remove source */
1109 * _wapi_daemon_main:
1111 * Open socket, create shared mem segment and begin listening for
1114 void _wapi_daemon_main(gpointer data, gpointer scratch)
1116 struct sockaddr_un main_socket_address;
1120 g_message ("Starting up...");
1123 _wapi_shared_data[0]=data;
1124 _wapi_shared_scratch=scratch;
1125 _wapi_shared_scratch->is_shared=TRUE;
1127 /* Note that we've got the starting segment already */
1128 _wapi_shared_data[0]->num_segments=1;
1129 _wapi_shm_mapped_segments=1;
1133 main_sock=socket(PF_UNIX, SOCK_STREAM, 0);
1135 main_socket_address.sun_family=AF_UNIX;
1136 memcpy(main_socket_address.sun_path, _wapi_shared_data[0]->daemon,
1137 MONO_SIZEOF_SUNPATH);
1139 ret=bind(main_sock, (struct sockaddr *)&main_socket_address,
1140 sizeof(struct sockaddr_un));
1142 g_critical ("bind failed: %s", g_strerror (errno));
1143 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1151 ret=listen(main_sock, 5);
1153 g_critical ("listen failed: %s", g_strerror (errno));
1154 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1159 g_message("listening");
1164 /* We're finished setting up, let everyone else know we're
1165 * ready. From now on, it's up to us to delete the shared
1166 * memory segment when appropriate.
1168 _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
1171 if(check_processes==TRUE) {
1176 g_message ("polling");
1179 /* Block until something happens. We don't use
1180 * g_main_loop_run() because we rely on the SIGCHLD
1181 * signal interrupting poll() so we can reap child
1182 * processes as soon as they die, without burning cpu
1183 * time by polling the flag.
1185 g_main_context_iteration (g_main_context_default (), TRUE);