static char rcsid[] = "$Id: process.c,v 1.1 1992/09/05 01:13:32 mike Exp $"; /* $Log: process.c,v $ * Revision 1.1 1992/09/05 01:13:32 mike * Initial revision * */ /* process.c : The part of ME2 that talks to the compute server. * C Durland 9/91 */ /* Copyright 1990, 1991, 1992 Craig Durland * Distributed under the terms of the GNU General Public License. * Distributed "as is", without warranties of any kind, but comments, * suggestions and bug reports are welcome. */ #include "config.h" #if !COMPUTE_SERVER #include "me2.h" #include "mm.h" extern MMDatum RV; /* in mm.c */ void create_process() { MMmsg("(create-process) not implemented!"); RV.type = NUMBER; RV.val.num = -1; return; } void process_talks() {} #else /* !COMPUTE_SERVER */ /* ******************************************************************** */ /* ************************** Compute Server ************************** */ /* ******************************************************************** */ #define _HPUX_SOURCE /* for ANSI C on HP-UX */ #include #include #include "me2.h" #include "mm.h" #include "../comserver/comserver.h" extern MMDatum RV, TV; /* in mm.c */ static int process_events(), events_pending(); static int client_socket = -1; /* (create-process ) * Output: * RV: * -1 : if no compute server, too many processes, some kind of * error, etc. * else: process-id * If no command, * (create-process) * Just open a connection to the compute server. * Output: * RV: * -1 : if no compute server * else: 0 * Returns: * zip. * Called from Mutt * Notes: * This routine uses Unix Domain Sockets. This means that there has * to be a well known socket (file) that both this code and the * compute server talk to. Since there can be lots of people each * running a ME2 and a compute server, the socket name needs to be * unique to each user. I can't use the $ME2 env var because it can * have more than one path in it so I use $HOME. To avoid clutter, * make it hidden. I use $HOME/.ME2.socket. */ void create_process() { extern char current_directory[], /* current directory, in os.c */ *getenv(); CSPacket packet; int pid; if (client_socket == -1) { char buf[300], *ptr; /* Create $HOME/.ME2.socket */ buf[0] = '\0'; if (ptr = getenv("HOME")) strcpy(buf,ptr); strcat(buf,"/.ME2.socket"); client_socket = CSopen_client_socket(buf,4); if (client_socket == -1) { MMmsg("Can't find Compute Server!"); RV.type = NUMBER; RV.val.num = -1; return; } CSbuild_packet(&packet, CS_SIGNAL, "nn", (int)getpid(), SIGUSR1); CSwrite_packet(&packet, client_socket); } /* Get the command, if there is one */ if (!maybearg(0,STRING,"create-process")) /* (create-process) */ { RV.type = NUMBER; RV.val.num = 0; return; } CSbuild_packet(&packet, CS_CREATE_PROCESS, "n", FALSE); CSwrite_packet(&packet, client_socket); /* Get process id */ pid = process_events(TRUE); if (pid == -1) { MMmsg("Can't create process!"); RV.type = NUMBER; RV.val.num = -1; return; } /* move the process to the current directory */ CSbuild_packet(&packet, CS_DIR, "s", current_directory); CSwrite_packet(&packet, client_socket); /* Send the command. I got it above. */ CSbuild_packet(&packet, CS_COMMAND, "s", TV.val.str); CSwrite_packet(&packet, client_socket); /* Start the command running */ CSbuild_packet(&packet, CS_DO_IT, ""); CSwrite_packet(&packet, client_socket); /* return the process id to the Mutt pgm */ RV.type = NUMBER; RV.val.num = pid; } void process_talks() { process_events(FALSE); } /* Suck events (from the compute server) out of the pipe and process * them. * Input: * waiting_for_pid : TRUE if sent a create process request to the * server and are waiting for the pid to be sent back. * Returns: * pid. Only if waiting_for_pid is TRUE. * you_don't_care otherwise. * Notes: * This stuff is kinda messy because it might be called from an * interrupt (while creating a new process) and should be * re-entrent. * Need to be careful when: * Error packets come though. * Am waiting for a pid and process-hook goes away or the socket * dies. */ static int process_events(waiting_for_pid) { extern int pro_hook; static int waiting = FALSE, piddle; CSPacket packet; int event_type, n, pid, error_code; MMStkFrame mark; xPacket event; /* Try and make this mess reentrent */ if (waiting) if (waiting_for_pid) { waiting = FALSE; return piddle; } else return 0; if (pro_hook == -1) return -1; /* No (process-hook) Mutt pgm */ if (client_socket == -1) { mlwrite("No client socket!"); return -1; } while (waiting_for_pid || events_pending()) { if (!CSread_packet(&packet, client_socket, &event)) { event.type = CS_ERROR; event.u.Error.pid = -1; event.u.Error.error_code = CS_ERROR_READ; } event_type = event.type; pid = event.u.Pid.pid; /* yuch! Get the pid all packets have */ if (event_type == CS_ERROR) { error_code = event.u.Error.error_code; switch (error_code) { case CS_ERROR_SERVER_DIED: mlwrite("Compute Server died!"); nuke_socket: n = close(client_socket); /* ??? error check */ client_socket = -1; break; case CS_ERROR_READ: case CS_ERROR_PROTOCOL: mlwrite("Compute Server: Data error!"); goto nuke_socket; } } /* Somebody did a create process and is waiting for this */ if (event_type == CS_PROCESS_ID) if (waiting_for_pid) return pid; else { waiting = TRUE; piddle = pid; return 0; } MMopen_frame(&mark); TV.type = NUMBER; TV.val.num = pid; MMpush_arg(&TV); TV.val.num = event_type; MMpush_arg(&TV); switch(event_type) { case CS_PROCESS_DONE: /* (process-hook pid PROCESS-DONE exit-status) */ n = event.u.ProcessDone.exit_code; TV.val.num = n; MMpush_arg(&TV); break; case CS_OUTPUT: /* (process-hook pid OUTPUT text) */ case CS_OUTPUT_ERR: /* (process-hook pid OUTPUT-ERR text) */ { char *ptr; ptr = event.u.Output.text; TV.type = STRING; TV.val.str = ptr; MMpush_arg(&TV); break; } case CS_CLIENT_MSG: /* (process-hook dud CLIENT_MSG tag text) */ { char *ptr; n = event.u.ClientMsg.tag; TV.val.num = n; MMpush_arg(&TV); ptr = event.u.ClientMsg.msg; TV.type = STRING; TV.val.str = ptr; MMpush_arg(&TV); break; } case CS_ERROR: /* (process-hook pid CS-ERROR error-code) */ TV.val.num = error_code; MMpush_arg(&TV); break; } MMrun_pgm_with_args(pro_hook,&mark); /* Oh yech! Handling errors is such a pain in the butt */ if (event_type == CS_ERROR) break; } return -1; } #if 0 exit_hook() /* ??? Should I use this? */ { CSPacket packet; if (client_socket == -1) return; CSbuild_packet(&packet, CS_DISCONNECT, ""); CSwrite_packet(&packet, client_socket); } #endif /* ******************************************************************** */ /* ************************** Client Socket *************************** */ /* ******************************************************************** */ #if BSD_OS || POSIX_OS || AIX_OS #include #else /* SYSV_OS */ #include #endif /* Check to see is anything waiting for me from the compute server. * Note: * If there is no socket (ie not talking to the compute server, this * code works and return 0; * Returns: * 0 : no events waiting * n : number of sockets with io waiting (1 in this case) */ #define MASK(f) (1 << (f)) static int events_pending() { int biggest_fd, n; struct timeval timeout; #if 0 if (client_socket == -1) return FALSE;/* ????????? */ #endif timeout.tv_sec = 0; timeout.tv_usec = 0; /* don't wait */ biggest_fd = client_socket +1; n = MASK(client_socket); n = select(biggest_fd, &n, 0, 0, &timeout); /* if (n == -1) ;/* error ??? */ return n; } #endif /* !COMPUTE_SERVER */