X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=kernel%2Fmonitor.c;h=d5579799cb429d6e79629c8ccf13bb1324de2197;hb=373495ef158d123d95ab44465d4249e65847492b;hp=9f5f79aa63cbfd17dbbcca02877b76f4e7e7d098;hpb=e7fd8016cc21ff4442a69c9dfc28b92ff8b3787f;p=egate.git diff --git a/kernel/monitor.c b/kernel/monitor.c index 9f5f79a..d557979 100644 --- a/kernel/monitor.c +++ b/kernel/monitor.c @@ -1,8 +1,91 @@ +/* + * Copyright (c) 1995, the EUROPAGATE consortium (see below). + * + * The EUROPAGATE consortium members are: + * + * University College Dublin + * Danmarks Teknologiske Videnscenter + * An Chomhairle Leabharlanna + * Consejo Superior de Investigaciones Cientificas + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation, in whole or in part, for any purpose, is hereby granted, + * provided that: + * + * 1. This copyright and permission notice appear in all copies of the + * software and its documentation. Notices of copyright or attribution + * which appear at the beginning of any file must remain unchanged. + * + * 2. The names of EUROPAGATE or the project partners may not be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * 3. Users of this software (implementors and gateway operators) agree to + * inform the EUROPAGATE consortium of their use of the software. This + * information will be used to evaluate the EUROPAGATE project and the + * software, and to plan further developments. The consortium may use + * the information in later publications. + * + * 4. Users of this software agree to make their best efforts, when + * documenting their use of the software, to acknowledge the EUROPAGATE + * consortium, and the role played by the software in their work. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE + * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF + * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA + * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND + * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE + * USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ /* Gateway Resource Monitor * Europagate, 1995 * * $Log: monitor.c,v $ - * Revision 1.3 1995/05/02 07:20:10 adam + * Revision 1.15 1995/07/11 11:49:12 adam + * LINE_MAX renamed to STR_LINE_MAX. + * + * Revision 1.14 1995/05/23 08:12:59 adam + * Minor changes. + * + * Revision 1.13 1995/05/22 11:42:48 adam + * Minor changes on dtbsun. + * + * Revision 1.12 1995/05/19 14:51:06 adam + * Bug fix: stopped kernels sometimes got IPC messages from the monitor. + * + * Revision 1.11 1995/05/19 13:26:00 adam + * Bug fixes. Better command line options. + * + * Revision 1.10 1995/05/18 12:03:09 adam + * Bug fixes and minor improvements. + * + * Revision 1.9 1995/05/17 10:51:32 adam + * Added a few more error checks to the show command. + * + * Revision 1.8 1995/05/16 09:40:42 adam + * LICENSE. Setting of CCL token names (and/or/not/set) in read_kernel_res. + * + * Revision 1.7 1995/05/03 12:18:46 adam + * This code ran on dtbsun. Minor changes. + * + * Revision 1.6 1995/05/03 09:16:17 adam + * Minor changes. + * + * Revision 1.5 1995/05/03 07:37:42 adam + * CCL commands stop/continue implemented. New functions gw_res_{int,bool} + * are used when possible. + * + * Revision 1.4 1995/05/02 15:26:00 adam + * Monitor observes death of child (email kernel). The number + * of simultanous processes is controlled now. Email requests are + * queued if necessary. This scheme should only be forced if no kernels + * are idle. + * + * Revision 1.3 1995/05/02 07:20:10 adam * Use pid of exited child to close fifos. * * Revision 1.2 1995/05/01 16:26:57 adam @@ -22,6 +105,7 @@ #include #include #include +#include #include #include @@ -30,26 +114,62 @@ #include #include -#include +#include #include #include #include -#define LINE_MAX 1024 +#define STR_LINE_MAX 1024 + +#define MONITOR_FIFO_S "fifo.s.m" +#define MONITOR_FIFO_C "fifo.c.m" static char *module = "monitor"; static jmp_buf retry_jmp; +static GwRes monitor_res = NULL; +static int no_process = 0; +static int max_process = 1; +static int got_sighup = 0; +static int got_term = 0; +static int got_int = 0; +const char *default_res = "default.res"; + +/* + * reread_resources: reread monitor resources. The static variable, + * max_process, is updated. + */ +static void reread_resources (void) +{ + if (monitor_res) + gw_res_close (monitor_res); + monitor_res = gw_res_init (); + if (gw_res_merge (monitor_res, default_res)) + { + gw_log (GW_LOG_WARN, module, "Couldn't read resource file %s", + default_res); + exit (1); + } + max_process = gw_res_int (monitor_res, "gw.max.process", 10); +} + struct ke_info { - pid_t pid; - int id; - GIP gip; - struct str_queue *queue; - struct ke_info *next; + int id; /* email user-id */ + int stopped; /* stop flag */ + pid_t pid; /* pid of email kernel child */ + GIP gip; /* fifo information */ + struct str_queue *queue; /* message queue */ + struct ke_info *next; /* link to next */ }; -struct ke_info *ke_info_list = NULL; +/* list of email kernel infos */ +static struct ke_info *ke_info_list = NULL; +/* + * ke_info_add: add/lookup of email kernel info. + * id: email user-id to search for. + * return: pointer to info structure. + */ struct ke_info *ke_info_add (int id) { struct ke_info **kip; @@ -62,15 +182,12 @@ struct ke_info *ke_info_add (int id) (*kip)->next = NULL; (*kip)->id = id; (*kip)->gip = NULL; - if (!((*kip)->queue = str_queue_mk ())) - { - gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "str_queue_mk"); - exit (1); - } + (*kip)->queue = NULL; + (*kip)->stopped = 0; return *kip; } -void ke_info_del (void) +static void ke_info_del (void) { struct ke_info *ki; @@ -81,31 +198,67 @@ void ke_info_del (void) free (ki); } -static void catchchild (int num) +/* + * catch_child: catch SIGCHLD. Set email kernel pid to -1 + * to indicate that child has exited + */ +static void catch_child (int num) { pid_t pid; struct ke_info *ki; while ((pid=waitpid (-1, 0, WNOHANG)) > 0) + { for (ki = ke_info_list; ki; ki = ki->next) if (ki->pid == pid) - { - gw_log (GW_LOG_DEBUG, module, "Close of %d", ki->id); - if (ki->gip) - { - gipc_close (ki->gip); - gipc_destroy (ki->gip); - ki->gip = NULL; - } - } - signal (SIGCHLD, catchchild); + ki->pid = -1; + --no_process; + } + signal (SIGCHLD, catch_child); +} + +/* + * catch_int: catch SIGHUP. + */ +static void catch_hup (int num) +{ + got_sighup = 1; + signal (SIGHUP, catch_hup); +} + +/* + * catch_int: catch SIGTERM. + */ +static void catch_term (int num) +{ + got_term = 1; + signal (SIGTERM, catch_term); } +/* + * catch_int: catch SIGINT. + */ +static void catch_int (int num) +{ + got_int = 1; + signal (SIGINT, catch_int); +} + +/* + * pipe_handle: handle SIGPIPE when transferring message to kernel + */ static void pipe_handle (int dummy) { longjmp (retry_jmp, 1); } +/* + * start_kernel: start email kernel. + * argc: argc of email kernel + * argv: argv of email kernel + * id: email user-id + * return: pid of email kernel child + */ static pid_t start_kernel (int argc, char **argv, int id) { pid_t pid; @@ -142,8 +295,29 @@ static pid_t start_kernel (int argc, char **argv, int id) return pid; } -static void deliver (int argc, char **argv, int id, struct str_queue *queue, - GIP *gip, pid_t *pidp) +/* + * deliver: deliver message to child (email kernel). + * argc: exec argc to child (if it need to be started) + * argv: exec argv to child (if it need to be started) + * id: email userid + * queue: message queue to be transferred + * gip: pointer to FIFO info. if *gip is NULL prior invocation + * it will be created (initialized) and the pointer will be + * updated. + * pidp: pointer to pid. Will hold process-id of child (if it need to + * be started) + * dont_exec: if non-zero a child will never be started; otherwise child + * will be started if not already running. + * return: 0 if message couldn't be transferred, i.e. dont_exec is non-zero + * and the child is not already running. + * 1 if message was transferred and the child was already running. + * 2 if message was transferred and the child was started and + * dont_exec was zero. + * 3 serious error. Permissions denied or kernel couldn't be + * started at all. + */ +static int deliver (int argc, char **argv, int id, struct str_queue *queue, + GIP *gip, pid_t *pidp, int dont_exec) { int pass = 0; int r; @@ -164,103 +338,188 @@ static void deliver (int argc, char **argv, int id, struct str_queue *queue, setjmp (retry_jmp); ++pass; if (pass == 1) - r = gipc_open (*gip, fifo_server_name, 0); + { /* assume child is running */ + gipc_close (*gip); /* shut down existing FIFOs */ + r = gipc_open (*gip, fifo_server_name, 0); /* try re-open ... */ + } else if (pass == 2) - { + { /* assume child is NOT running */ pid_t pid; + if (dont_exec) + { /* we aren't allowed to start */ + signal (SIGPIPE, oldsig); + return 0; + } mknod (fifo_server_name, S_IFIFO|0666, 0); pid = start_kernel (argc, argv, id); - if (pidp) + if (pidp) /* set pid of child */ *pidp = pid; r = gipc_open (*gip, fifo_server_name, 1); } else - { + { /* message couldn't be transferred */ + signal (SIGPIPE, oldsig); gw_log (GW_LOG_WARN, module, "Cannot start kernel"); - return; + return 3; } - if (r < 0) + if (r < 0) /* gipc_open fail? */ { if (r == -2) - { gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "r==-2"); - longjmp (retry_jmp, 1); - } else if (r == -1) - { gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "r==-1"); - longjmp (retry_jmp, 1); - } else - { gw_log (GW_LOG_WARN|GW_LOG_ERRNO, module, "gipc_open"); - return; - } + longjmp (retry_jmp, 1); /* yet another pass */ } - index = 0; + index = 0; /* transfer. may be interrupted */ while ((msg = str_queue_get (queue, index++))) + { + gw_log (GW_LOG_DEBUG, module, "deliver: %s", msg); gip_wline (*gip, msg); + } signal (SIGPIPE, oldsig); + return pass; /* successful transfer */ } +/* + * monitor_events: Event loop of monitor + * argc: argc of monitor (used in exec of Email kernel children) + * argv: argv of monitor (used in exec of Email kernel children) + */ static void monitor_events (int argc, char **argv) { GIP gip_m; - int r, gip_m_fd; + int r, gip_m_fd, too_many; char line_buf[1024]; fd_set set_r; char command[128], *cp; - int no_process = 0; - int max_process = 4; - gip_m = gips_initialize ("fifo.s"); - r = gips_open (gip_m, "fifo.c"); + mknod (MONITOR_FIFO_C, S_IFIFO|0666, 0); + open (MONITOR_FIFO_C, O_RDONLY|O_NONBLOCK); + gip_m = gips_initialize (MONITOR_FIFO_S); + r = gips_open (gip_m, MONITOR_FIFO_C, 0); gip_m_fd = gip_infileno (gip_m); - open ("fifo.s", O_WRONLY); - +#if 1 + open (MONITOR_FIFO_S, O_WRONLY); +#endif + gw_log (GW_LOG_DEBUG, module, "Starting event loop"); while (1) { int fd_max; struct ke_info *ki; - while (1) + while (1) { - FD_ZERO (&set_r); - FD_SET (gip_m_fd, &set_r); - gw_log (GW_LOG_DEBUG, module, "set r %d", gip_m_fd); - fd_max = gip_m_fd; - + if (got_sighup) + { + gw_log (GW_LOG_STAT, module, "Got SIGHUP. Reading resources"); + reread_resources (); + got_sighup = 0; + } + if (got_term) + { + gw_log (GW_LOG_STAT, module, "Got SIGTERM. Exiting..."); + unlink (MONITOR_FIFO_S); + unlink (MONITOR_FIFO_C); + exit (0); + } + if (got_int) + { + gw_log (GW_LOG_STAT, module, "Got SIGINT. Exiting..."); + unlink (MONITOR_FIFO_S); + unlink (MONITOR_FIFO_C); + exit (0); + } + /* deliver any unsent messages to Email kernels */ + too_many = 0; for (ki = ke_info_list; ki; ki = ki->next) { - if (!ki->queue) + if (!ki->queue || ki->stopped) continue; gw_log (GW_LOG_DEBUG, module, "Transfer mail to %d", ki->id); - deliver (argc, argv, ki->id, ki->queue, &ki->gip, &ki->pid); - str_queue_rm (&ki->queue); + r = deliver (argc, argv, ki->id, ki->queue, &ki->gip, &ki->pid, + no_process >= max_process); + if (r == 2) /* new child was spawned? */ + { + ++no_process; + gw_log (GW_LOG_DEBUG, module, "Start of %d", ki->id); + } + if (r == 1 || r == 2) /* transfer at all? */ + str_queue_rm (&ki->queue); + if (r == 0) /* too many pending? */ + too_many++; + } + if (too_many) + { + gw_log (GW_LOG_DEBUG, module, "%d too many pending", + too_many); + for (ki = ke_info_list; ki; ki = ki->next) + { + if (!ki->queue && ki->pid != -1 && !ki->stopped) + { + if (!(ki->queue = str_queue_mk ())) + { + gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, + "str_queue_mk"); + exit (1); + } + str_queue_enq (ki->queue, "stop\n"); + str_queue_enq (ki->queue, "\001"); + r = deliver (argc, argv, ki->id, ki->queue, &ki->gip, + &ki->pid, 1); + if (r != 1) + gw_log (GW_LOG_DEBUG, module, + "Stop not sent: %d", r); + str_queue_rm (&ki->queue); + ki->stopped = 1; + break; + } + } } + FD_ZERO (&set_r); + FD_SET (gip_m_fd, &set_r); + gw_log (GW_LOG_DEBUG, module, "set gip_m_fd %d", gip_m_fd); + fd_max = gip_m_fd; + for (ki = ke_info_list; ki; ki = ki->next) { int fd; - if (ki->gip && (fd = gip_infileno (ki->gip)) != -1) + if (ki->gip) { - gw_log (GW_LOG_DEBUG, module, "set r %d", fd); - FD_SET (fd, &set_r); - if (fd > fd_max) - fd_max = fd; + if (ki->pid == -1) + { /* child has exited */ + gw_log (GW_LOG_DEBUG, module, "Close of %d", ki->id); + gipc_close (ki->gip); + gipc_destroy (ki->gip); + ki->gip = NULL; + ki->stopped = 0; + } + else if ((fd = gip_infileno (ki->gip)) != -1) + { /* read select on child FIFO */ + gw_log (GW_LOG_DEBUG, module, "set fd %d", fd); + FD_SET (fd, &set_r); + if (fd > fd_max) + fd_max = fd; + } } } + gw_log (GW_LOG_DEBUG, module, "Cur/Max processes %d/%d", + no_process, max_process); gw_log (GW_LOG_DEBUG, module, "IPC select"); r = select (fd_max+1, &set_r, NULL, NULL, NULL); if (r != -1) break; if (errno != EINTR) - { + { /* select aborted. And it was not due to interrupt */ gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "select"); exit (1); } + /* select was interrupted. Probably child has died */ gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "select"); } + /* go through list of Email kernels. See if any message has arrived */ gw_log (GW_LOG_DEBUG, module, "Testing ke_info_list"); for (ki = ke_info_list; ki; ki = ki->next) { @@ -280,11 +539,12 @@ static void monitor_events (int argc, char **argv) gipc_close (ki->gip); gipc_destroy (ki->gip); ki->gip = NULL; + ki->stopped = 0; } } } } - + /* see if any message from eti has arrived */ gw_log (GW_LOG_DEBUG, module, "Testing gip_m_fd %d", gip_m_fd); if (FD_ISSET (gip_m_fd, &set_r)) { @@ -305,6 +565,16 @@ static void monitor_events (int argc, char **argv) new_k = ke_info_add (id); gw_log (GW_LOG_DEBUG, module, "Incoming mail %d", id); + + if (!new_k->queue) + { + if (!(new_k->queue = str_queue_mk ())) + { + gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, + "str_queue_mk"); + exit (1); + } + } str_queue_enq (new_k->queue, "mail\n"); while (lgets (line_buf, sizeof(line_buf)-1, gip_m_fd)) str_queue_enq (new_k->queue, line_buf); @@ -314,18 +584,66 @@ static void monitor_events (int argc, char **argv) } } +/* + * main: main of monitor + */ int main (int argc, char **argv) { + int argno = 0; + gw_log_init (*argv); - gw_log_level (GW_LOG_ALL); - signal (SIGCHLD, catchchild); -#if 0 - gw_log_file (GW_LOG_ALL, "monitor.log"); -#endif - monitor_events (argc, argv); + while (++argno < argc) + { + if (argv[argno][0] == '-') + { + if (argv[argno][1] == '-') + break; + switch (argv[argno][1]) + { + case 'h': + case 'H': + fprintf (stderr, "monitor [options] [resourceFile]" + " -- [kernelOptions]\n"); + fprintf (stderr, "If no resource file is specified"); + fprintf (stderr, " default.res is used\n"); + fprintf (stderr, "Options:\n"); + fprintf (stderr, " -l log Set Log file\n"); + fprintf (stderr, " -d Enable debugging log\n"); + fprintf (stderr, " -D Enable more debugging log\n"); + fprintf (stderr, " -- Precedes kernel options\n"); + fprintf (stderr, "Kernel options are transferred to kernel\n"); + exit (1); + case 'l': + if (argv[argno][2]) + gw_log_file (GW_LOG_ALL, argv[argno]+2); + else if (++argno < argc) + gw_log_file (GW_LOG_ALL, argv[argno]); + else + { + fprintf (stderr, "%s: missing log filename\n", *argv); + exit (1); + } + break; + case 'd': + gw_log_level (GW_LOG_ALL & ~RES_DEBUG); + break; + case 'D': + gw_log_level (GW_LOG_ALL); + break; + default: + fprintf (stderr, "%s: unknown option `%s'; use -H for help\n", + *argv, argv[argno]); + exit (1); + } + } + else + default_res = argv[argno]; + } + reread_resources (); + signal (SIGCHLD, catch_child); + signal (SIGHUP, catch_hup); + signal (SIGTERM, catch_term); + signal (SIGINT, catch_int); + monitor_events (argc-argno, argv+argno); exit (0); } - - - -