• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • Directories
  • File List
  • Globals

pt.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Process Table
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  *
00008  * Permission to use, copy, modify, and distribute this software for any
00009  * purpose with or without fee is hereby granted, provided that the above
00010  * copyright notice and this permission notice appear in all copies.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00013  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00014  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00015  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00016  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00017  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00018  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00019  */
00020 /*
00021  * History:
00022  * --------
00023  *  2006-06-14  added process table in shared mem (dragos)
00024  *  2006-09-20  added profile support (-DPROFILING) (hscholz)
00025  *  2006-10-25  sanity check before allowing forking w/ tcp support (is_main
00026  *               & tcp not started yet); set is_main=0 in childs (andrei)
00027  *  2007-07-04  added register_fds() and get_max_open_fds(() (andrei)
00028  *  2010-08-19  use daemon_status_on_fork_cleanup() (andrei)
00029  */
00036 #include "pt.h"
00037 #include "tcp_init.h"
00038 #include "sr_module.h"
00039 #include "socket_info.h"
00040 #include "rand/fastrand.h"
00041 #ifdef PKG_MALLOC
00042 #include "mem/mem.h"
00043 #endif
00044 #ifdef SHM_MEM
00045 #include "mem/shm_mem.h"
00046 #endif
00047 #if defined PKG_MALLOC || defined SHM_MEM
00048 #include "cfg_core.h"
00049 #endif
00050 #include "daemonize.h"
00051 
00052 #include <stdio.h>
00053 #include <time.h> /* time(), used to initialize random numbers */
00054 
00055 #define FORK_DONT_WAIT  /* child doesn't wait for parent before starting 
00056                                                    => faster startup, but the child should not assume
00057                                                    the parent fixed the pt[] entry for it */
00058 
00059 
00060 #ifdef PROFILING
00061 #include <sys/gmon.h>
00062 
00063         extern void _start(void);
00064         extern void etext(void);
00065 #endif
00066 
00067 
00068 static int estimated_proc_no=0;
00069 static int estimated_fds_no=0;
00070 
00071 /* number of usec to wait before forking a process */
00072 static unsigned int fork_delay = 0;
00073 
00074 unsigned int set_fork_delay(unsigned int v)
00075 {
00076         unsigned int r;
00077         r =  fork_delay;
00078         fork_delay = v;
00079         return r;
00080 }
00081 
00082 /* number of known "common" used fds */
00083 static int calc_common_open_fds_no(void)
00084 {
00085         int max_fds_no;
00086         
00087         /* 1 tcp send unix socket/all_proc, 
00088          *  + 1 udp sock/udp proc + 1 possible dns comm. socket + 
00089          *  + 1 temporary tcp send sock.
00090          * Per process:
00091          *  + 1 if mhomed (now mhomed keeps a "cached socket" per process)
00092          *  + 1 if mhomed & ipv6
00093          */
00094         max_fds_no=estimated_proc_no*4 /* udp|sctp + tcp unix sock +
00095                                                                           tmp. tcp send +
00096                                                                           tmp dns.*/
00097                                 -1 /* timer (no udp)*/ + 3 /* stdin/out/err */ +
00098 #ifdef USE_IPV6
00099                                 2*mhomed
00100 #else
00101                                 mhomed
00102 #endif /* USE_IPV6*/
00103                                 ;
00104         return max_fds_no;
00105 }
00106 
00107 
00108 
00109 /* returns 0 on success, -1 on error */
00110 int init_pt(int proc_no)
00111 {
00112 #ifdef USE_TCP
00113         int r;
00114 #endif
00115         
00116         estimated_proc_no+=proc_no;
00117         estimated_fds_no+=calc_common_open_fds_no();
00118         /*alloc pids*/
00119 #ifdef SHM_MEM
00120         pt=shm_malloc(sizeof(struct process_table)*estimated_proc_no);
00121         process_count = shm_malloc(sizeof(int));
00122 #else
00123         pt=pkg_malloc(sizeof(struct process_table)*estimated_proc_no);
00124         process_count = pkg_malloc(sizeof(int));
00125 #endif
00126         process_lock = lock_alloc();
00127         process_lock = lock_init(process_lock);
00128         if (pt==0||process_count==0||process_lock==0){
00129                 LOG(L_ERR, "ERROR: out  of memory\n");
00130                 return -1;
00131         }
00132         memset(pt, 0, sizeof(struct process_table)*estimated_proc_no);
00133 #ifdef USE_TCP
00134         for (r=0; r<estimated_proc_no; r++){
00135                 pt[r].unix_sock=-1;
00136                 pt[r].idx=-1;
00137         }
00138 #endif
00139         process_no=0; /*main process number*/
00140         pt[process_no].pid=getpid();
00141         memcpy(pt[process_no].desc,"main",5);
00142         *process_count=1;
00143         return 0;
00144 }
00145 
00146 
00147 /* register no processes, used from mod_init when processes will be forked
00148  *  from mod_child 
00149  *  returns 0 on success, -1 on error
00150  */
00151 int register_procs(int no)
00152 {
00153         if (pt){
00154                 LOG(L_CRIT, "BUG: register_procs(%d) called at runtime\n", no);
00155                 return -1;
00156         }
00157         estimated_proc_no+=no;
00158         return 0;
00159 }
00160 
00161 
00162 
00163 /* returns the maximum number of processes */
00164 int get_max_procs()
00165 {
00166         if (pt==0){
00167                 LOG(L_CRIT, "BUG: get_max_procs() called too early "
00168                                 "(it must _not_ be called from mod_init())\n");
00169                 abort(); /* crash to quickly catch offenders */
00170         }
00171         return estimated_proc_no;
00172 }
00173 
00174 
00175 /* register no fds, used from mod_init when modules will open more global
00176  *  fds (from mod_init or child_init(PROC_INIT)
00177  *  or from child_init(rank) when the module will open fds local to the
00178  *   process "rank".
00179  *   (this is needed because some other parts of ser code rely on knowing
00180  *    the maximum open fd number in a process)
00181  *  returns 0 on success, -1 on error
00182  */
00183 int register_fds(int no)
00184 {
00185         /* can be called at runtime, but should be called from child_init() */
00186         estimated_fds_no+=no;
00187         return 0;
00188 }
00189 
00190 
00191 
00192 /* returns the maximum open fd number */
00193 int get_max_open_fds()
00194 {
00195         if (pt==0){
00196                 LOG(L_CRIT, "BUG: get_max_open_fds() called too early "
00197                                 "(it must _not_ be called from mod_init())\n");
00198                 abort(); /* crash to quickly catch offenders */
00199         }
00200         return estimated_fds_no;
00201 }
00202 
00203 
00204 /* return processes pid */
00205 int my_pid()
00206 {
00207         return pt ? pt[process_no].pid : getpid();
00208 }
00209 
00210 
00211 
00212 /* close unneeded sockets */
00213 int close_extra_socks(int child_id, int proc_no)
00214 {
00215 #ifdef USE_TCP
00216         int r;
00217         struct socket_info* si;
00218         
00219         if (child_id!=PROC_TCP_MAIN){
00220                 for (r=0; r<proc_no; r++){
00221                         if (pt[r].unix_sock>=0){
00222                                 /* we can't change the value in pt[] because it's
00223                                  * shared so we only close it */
00224                                 close(pt[r].unix_sock);
00225                         }
00226                 }
00227                 /* close all listen sockets (needed only in tcp_main */
00228                 if (!tcp_disable){
00229                         for(si=tcp_listen; si; si=si->next){
00230                                 close(si->socket);
00231                                 /* safe to change since this is a per process copy */
00232                                 si->socket=-1;
00233                         }
00234 #ifdef USE_TLS
00235                         if (!tls_disable){
00236                                 for(si=tls_listen; si; si=si->next){
00237                                         close(si->socket);
00238                                         /* safe to change since this is a per process copy */
00239                                         si->socket=-1;
00240                                 }
00241                         }
00242 #endif /* USE_TLS */
00243                 }
00244                 /* we still need the udp sockets (for sending) so we don't close them
00245                  * too */
00246         }
00247 #endif /* USE_TCP */
00248         return 0;
00249 }
00250 
00251 
00252 
00261 int fork_process(int child_id, char *desc, int make_sock)
00262 {
00263         int pid, child_process_no;
00264         int ret;
00265         unsigned int new_seed1;
00266         unsigned int new_seed2;
00267 #ifdef USE_TCP
00268         int sockfd[2];
00269 #endif
00270 
00271         if(unlikely(fork_delay>0))
00272                 sleep_us(fork_delay);
00273 
00274         ret=-1;
00275         #ifdef USE_TCP
00276                 sockfd[0]=sockfd[1]=-1;
00277                 if(make_sock && !tcp_disable){
00278                          if (!is_main){
00279                                  LOG(L_CRIT, "BUG: fork_process(..., 1) called from a non "
00280                                                  "\"main\" process! If forking from a module's "
00281                                                  "child_init() fork only if rank==PROC_MAIN or"
00282                                                  " give up tcp send support (use 0 for make_sock)\n");
00283                                  goto error;
00284                          }
00285                          if (tcp_main_pid){
00286                                  LOG(L_CRIT, "BUG: fork_process(..., 1) called, but tcp main "
00287                                                  " is already started\n");
00288                                  goto error;
00289                          }
00290                          if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
00291                                 LOG(L_ERR, "ERROR: fork_process(): socketpair failed: %s\n",
00292                                                         strerror(errno));
00293                                 goto error;
00294                         }
00295                 }
00296         #endif
00297         lock_get(process_lock);
00298         if (*process_count>=estimated_proc_no) {
00299                 LOG(L_CRIT, "ERROR: fork_process(): Process limit of %d exceeded."
00300                                         " Will simulate fork fail.\n", estimated_proc_no);
00301                 lock_release(process_lock);
00302                 goto error;
00303         }       
00304         
00305         
00306         child_process_no = *process_count;
00307         new_seed1=rand();
00308         new_seed2=random();
00309         pid = fork();
00310         if (pid<0) {
00311                 lock_release(process_lock);
00312                 ret=pid;
00313                 goto error;
00314         }else if (pid==0){
00315                 /* child */
00316                 is_main=0; /* a forked process cannot be the "main" one */
00317                 process_no=child_process_no;
00318                 daemon_status_on_fork_cleanup();
00319                 /* close tcp unix sockets if this is not tcp main */
00320 #ifdef USE_TCP
00321                 close_extra_socks(child_id, process_no);
00322 #endif /* USE_TCP */
00323                 srand(new_seed1);
00324                 fastrand_seed(rand());
00325                 srandom(new_seed2+time(0));
00326                 shm_malloc_on_fork();
00327 #ifdef PROFILING
00328                 monstartup((u_long) &_start, (u_long) &etext);
00329 #endif
00330 #ifdef FORK_DONT_WAIT
00331                 /* record pid twice to avoid the child using it, before
00332                  * parent gets a chance to set it*/
00333                 pt[process_no].pid=getpid();
00334 #else
00335                 /* wait for parent to get out of critical zone.
00336                  * this is actually relevant as the parent updates
00337                  * the pt & process_count. */
00338                 lock_get(process_lock);
00339                 lock_release(process_lock);
00340 #endif
00341                 #ifdef USE_TCP
00342                         if (make_sock && !tcp_disable){
00343                                 close(sockfd[0]);
00344                                 unix_tcp_sock=sockfd[1];
00345                         }
00346                 #endif          
00347                 if ((child_id!=PROC_NOCHLDINIT) && (init_child(child_id) < 0)) {
00348                         LOG(L_ERR, "ERROR: fork_process(): init_child failed for "
00349                                         " process %d, pid %d, \"%s\"\n", process_no,
00350                                         pt[process_no].pid, pt[process_no].desc);
00351                         return -1;
00352                 }
00353                 return pid;
00354         } else {
00355                 /* parent */
00356                 (*process_count)++;
00357 #ifdef FORK_DONT_WAIT
00358                 lock_release(process_lock);
00359 #endif
00360                 /* add the process to the list in shm */
00361                 pt[child_process_no].pid=pid;
00362                 if (desc){
00363                         strncpy(pt[child_process_no].desc, desc, MAX_PT_DESC);
00364                 }
00365                 #ifdef USE_TCP
00366                         if (make_sock && !tcp_disable){
00367                                 close(sockfd[1]);
00368                                 pt[child_process_no].unix_sock=sockfd[0];
00369                                 pt[child_process_no].idx=-1; /* this is not a "tcp" process*/
00370                         }
00371                 #endif
00372 #ifdef FORK_DONT_WAIT
00373 #else
00374                 lock_release(process_lock);
00375 #endif
00376                 ret=pid;
00377                 goto end;
00378         }
00379 error:
00380 #ifdef USE_TCP
00381         if (sockfd[0]!=-1) close(sockfd[0]);
00382         if (sockfd[1]!=-1) close(sockfd[1]);
00383 #endif
00384 end:
00385         return ret;
00386 }
00387 
00395 #ifdef USE_TCP
00396 int fork_tcp_process(int child_id, char *desc, int r, int *reader_fd_1)
00397 {
00398         int pid, child_process_no;
00399         int sockfd[2];
00400         int reader_fd[2]; /* for comm. with the tcp children read  */
00401         int ret;
00402         int i;
00403         unsigned int new_seed1;
00404         unsigned int new_seed2;
00405         
00406         /* init */
00407         sockfd[0]=sockfd[1]=-1;
00408         reader_fd[0]=reader_fd[1]=-1;
00409         ret=-1;
00410         
00411         if (!is_main){
00412                  LOG(L_CRIT, "BUG: fork_tcp_process() called from a non \"main\" "
00413                                         "process\n");
00414                  goto error;
00415          }
00416          if (tcp_main_pid){
00417                  LOG(L_CRIT, "BUG: fork_tcp_process(..., 1) called _after_ starting"
00418                                         " tcp main\n");
00419                  goto error;
00420          }
00421         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
00422                 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
00423                                         strerror(errno));
00424                 goto error;
00425         }
00426         if (socketpair(AF_UNIX, SOCK_STREAM, 0, reader_fd)<0){
00427                 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
00428                                         strerror(errno));
00429                 goto error;
00430         }
00431         if (tcp_fix_child_sockets(reader_fd)<0){
00432                 LOG(L_ERR, "ERROR: fork_tcp_process(): failed to set non blocking"
00433                                         "on child sockets\n");
00434                 /* continue, it's not critical (it will go slower under
00435                  * very high connection rates) */
00436         }
00437         lock_get(process_lock);
00438         /* set the local process_no */
00439         if (*process_count>=estimated_proc_no) {
00440                 LOG(L_CRIT, "ERROR: fork_tcp_process(): Process limit of %d exceeded."
00441                                         " Simulating fork fail\n", estimated_proc_no);
00442                 lock_release(process_lock);
00443                 goto error;
00444         }
00445         
00446         
00447         child_process_no = *process_count;
00448         new_seed1=rand();
00449         new_seed2=random();
00450         pid = fork();
00451         if (pid<0) {
00452                 lock_release(process_lock);
00453                 ret=pid;
00454                 goto end;
00455         }
00456         if (pid==0){
00457                 is_main=0; /* a forked process cannot be the "main" one */
00458                 process_no=child_process_no;
00459                 /* close unneeded unix sockets */
00460                 close_extra_socks(child_id, process_no);
00461                 /* same for unneeded tcp_children <-> tcp_main unix socks */
00462                 for (i=0; i<r; i++){
00463                         if (tcp_children[i].unix_sock>=0){
00464                                 close(tcp_children[i].unix_sock);
00465                                 /* tcp_children is per process, so it's safe to change
00466                                  * the unix_sock to -1 */
00467                                 tcp_children[i].unix_sock=-1;
00468                         }
00469                 }
00470                 daemon_status_on_fork_cleanup();
00471                 srand(new_seed1);
00472                 fastrand_seed(rand());
00473                 srandom(new_seed2+time(0));
00474                 shm_malloc_on_fork();
00475 #ifdef PROFILING
00476                 monstartup((u_long) &_start, (u_long) &etext);
00477 #endif
00478 #ifdef FORK_DONT_WAIT
00479                 /* record pid twice to avoid the child using it, before
00480 -                * parent gets a chance to set it*/
00481                 pt[process_no].pid=getpid();
00482 #else
00483                 /* wait for parent to get out of critical zone */
00484                 lock_get(process_lock);
00485                 lock_release(process_lock);
00486 #endif
00487                 close(sockfd[0]);
00488                 unix_tcp_sock=sockfd[1];
00489                 close(reader_fd[0]);
00490                 if (reader_fd_1) *reader_fd_1=reader_fd[1];
00491                 if ((child_id!=PROC_NOCHLDINIT) && (init_child(child_id) < 0)) {
00492                         LOG(L_ERR, "ERROR: fork_tcp_process(): init_child failed for "
00493                                         "process %d, pid %d, \"%s\"\n", process_no, 
00494                                         pt[process_no].pid, pt[process_no].desc);
00495                         return -1;
00496                 }
00497                 return pid;
00498         } else {
00499                 /* parent */
00500                 (*process_count)++;
00501 #ifdef FORK_DONT_WAIT
00502                 lock_release(process_lock);
00503 #endif
00504                 /* add the process to the list in shm */
00505                 pt[child_process_no].pid=pid;
00506                 pt[child_process_no].unix_sock=sockfd[0];
00507                 pt[child_process_no].idx=r;
00508                 if (desc){
00509                         snprintf(pt[child_process_no].desc, MAX_PT_DESC, "%s child=%d", 
00510                                                 desc, r);
00511                 }
00512 #ifdef FORK_DONT_WAIT
00513 #else
00514                 lock_release(process_lock);
00515 #endif
00516                 
00517                 close(sockfd[1]);
00518                 close(reader_fd[1]);
00519                 
00520                 tcp_children[r].pid=pid;
00521                 tcp_children[r].proc_no=child_process_no;
00522                 tcp_children[r].busy=0;
00523                 tcp_children[r].n_reqs=0;
00524                 tcp_children[r].unix_sock=reader_fd[0];
00525                 
00526                 ret=pid;
00527                 goto end;
00528         }
00529 error:
00530         if (sockfd[0]!=-1) close(sockfd[0]);
00531         if (sockfd[1]!=-1) close(sockfd[1]);
00532         if (reader_fd[0]!=-1) close(reader_fd[0]);
00533         if (reader_fd[1]!=-1) close(reader_fd[1]);
00534 end:
00535         return ret;
00536 }
00537 #endif
00538 
00539 #ifdef PKG_MALLOC
00540 /* Dumps pkg memory status.
00541  * Per-child process callback that is called
00542  * when mem_dump_pkg cfg var is changed.
00543  */
00544 void mem_dump_pkg_cb(str *gname, str *name)
00545 {
00546         int     old_memlog;
00547         int memlog;
00548 
00549         if (cfg_get(core, core_cfg, mem_dump_pkg) == my_pid()) {
00550                 /* set memlog to ALERT level to force
00551                 printing the log messages */
00552                 old_memlog = cfg_get(core, core_cfg, memlog);
00553                 memlog = L_ALERT;
00554                 /* ugly hack to temporarily switch memlog to something visible,
00555                    possible race with a parallel cfg_set */
00556                 ((struct cfg_group_core*)core_cfg)->memlog=memlog;
00557 
00558                 LOG(memlog, "Memory status (pkg) of process %d:\n", my_pid());
00559                 pkg_status();
00560 
00561                 ((struct cfg_group_core*)core_cfg)->memlog=old_memlog;
00562         }
00563 }
00564 #endif
00565 
00566 #ifdef SHM_MEM
00567 /* Dumps shm memory status.
00568  * fixup function that is called
00569  * when mem_dump_shm cfg var is set.
00570  */
00571 int mem_dump_shm_fixup(void *handle, str *gname, str *name, void **val)
00572 {
00573         int     old_memlog;
00574         int memlog;
00575 
00576         if ((long)(void*)(*val)) {
00577                 /* set memlog to ALERT level to force
00578                 printing the log messages */
00579                 old_memlog = cfg_get(core, core_cfg, memlog);
00580                 memlog = L_ALERT;
00581                 /* ugly hack to temporarily switch memlog to something visible,
00582                    possible race with a parallel cfg_set */
00583                 ((struct cfg_group_core*)core_cfg)->memlog=memlog;
00584 
00585                 LOG(memlog, "Memory status (shm)\n");
00586                 shm_status();
00587 
00588                 ((struct cfg_group_core*)core_cfg)->memlog=old_memlog;
00589                 *val = (void*)(long)0;
00590         }
00591         return 0;
00592 }
00593 #endif

Generated on Tue May 22 2012 13:10:13 for SIP Router by  doxygen 1.7.1