📄 forking.c
字号:
/* TradeClient <http://tradeclient.sourceforge.net> * $Id: forking.c,v 1.77 2001/03/20 22:19:33 ttabner Exp $ * * Copyright (C) 1999-2000 Bynari Inc. * Copyright (C) 2001 Project TradeClient * * LGPL * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library * General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "puma.h"#include "ipc.h"/* * Notice that our queue implementation is actually a FIFO! */static QueList *quelist = NULL ;static int queSafe = -1 ; /* * Init the mutex used by the queue here */voidque_sem_init( void ){ queSafe = initSem() ; return ;}/* * Release the system resource held by the IPC semaphore */voidque_sem_deinit( void ){ deInitSem( queSafe ) ; return ;}/* These functions are now thread/process safe. It seems * Alex and Andrew had no concept of concurrent/parallel programming. * As such, everything they touched is broken from a concurrent/SMP * perspective. On top of that, it's poorly written!!! We shouldn't * be making yet ANOTHER copy of the message. We should be storing * a pointer to it, whereby, we become the owners of it. */void que_message (char *msg) { QueList *queseek ;#if DEBUG > 4 int depth = 0 ;#endif lockSem( queSafe ) ; queseek = quelist ;#ifdef DMALLOC dmalloc_verify( 0 ) ;#endif if (queseek==NULL) { quelist=(QueList *)calloc (1, sizeof(QueList)); quelist -> data = msg ; quelist -> length = strlen( msg ) ;#if DEBUG > 4 depth++ ;#endif } else { while( queseek -> next ) {#if DEBUG > 4 depth++ ;#endif queseek = queseek -> next ; } queseek -> next = (QueList *)calloc ( 1, sizeof(QueList) ) ; queseek -> next -> data = msg ; queseek -> length = strlen( msg ) ; }#ifdef DMALLOC dmalloc_verify( 0 ) ;#endif#if DEBUG > 4 printf( "********************************> Message queue depth of %d.\n", depth ) ;#endif unlockSem( queSafe ) ; return ;}/* These functions are now thread/process safe. It seems * Alex and Andrew had no concept of concurrent/parallel programming. * As such, everything they touched is broken from a concurrent/SMP * perspective. On top of that, it's poorly written!!! We shouldn't * be making yet ANOTHER copy of the message. We should be storing * a pointer to it, whereby, we become the owners of it. * This function takes the message on the head of the list, removes * it from the queue and returns a pointer to it. At this point in * time, the caller becomes the owner of the message. */char *deque_message( void ) { QueList *q ; char *ptr ; lockSem( queSafe ) ; q = quelist ; if( q ) { quelist = q -> next ; } unlockSem( queSafe ) ;#if DEBUG > 4 printf( "Dequeing a message of %ld bytes long...\n", q -> length ) ; printf( "Dequeing a message of %ld bytes long...\n", q -> length ) ; printf( "Dequeing a message of %ld bytes long...\n", q -> length ) ; printf( "Dequeing a message of %ld bytes long...\n", q -> length ) ; printf( "Dequeing a message of %ld bytes long...\n", q -> length ) ; printf( "Dequeing a message of %ld bytes long...\n", q -> length ) ;#endif ptr = q -> data ; free( q ) ;#ifdef DMALLOC dmalloc_verify( 0 ) ;#endif return ptr ;}/* These functions are now thread/process safe. It seems * Alex and Andrew had no concept of concurrent/parallel programming. * As such, everything they touched is broken from a concurrent/SMP * perspective. On top of that, it's poorly written!!! We shouldn't * be making yet ANOTHER copy of the message. We should be storing * a pointer to it, whereby, we become the owners of it. */voidque_remove( void ) { long cnt ; QueList *qtemp; cnt = 0 ; lockSem( queSafe ) ;#ifdef DEBUG if( quelist ) printf( "We have at least one message to remove.\n" ) ; else printf( "No messages to remove!\n" ) ;#endif while( quelist ) { qtemp = quelist ; quelist = quelist -> next ; free( qtemp -> data ) ; free( qtemp ) ; cnt++ ; } unlockSem( queSafe ) ;#ifdef DMALLOC dmalloc_verify( 0 ) ;#endif#ifdef DEBUG printf( "que_remove() purged %ld messages.\n", cnt ) ;#endif return ;}#ifdef DEBUG#define DEBUGFORK 0#endif/* Loop through all of the accounts and take action if needed. * Notice that we will not be having a duplicated effort of what * fork_receive_message1() does (duh...that would be **VERY** stupid). * In fact, we will make use of it to keep it simple!!!! */void fork_receive_messages( int id ){ int pid ;#if DEBUGFORK > 0 int debugger ;#endif char *snum ; int childStat ; PopAccount *curpop ; /* See if we need to process any OOOREAD requests */ get_message_timeout( NULL ) ; /* Synch fix? */ if( tm_globs -> pid != -1 ) return ; /* Now, create a child process to get junk for all accounts */ if( (pid = fork()) == 0 ) {#if DEBUGFORK > 0 /* Here for debugging only - this requires the debugger to change the value!!!! */ debugger = 1 ; while( debugger ) { printf( "Waiting on the debugger to save me on pid #%d in fork_receive_messages().\n", getpid() ) ; sleep( 1 ) ; }#endif /* Get the first account record */ curpop = (id ? seek_popaccount (id) : first_popaccount()); /* Now, walk through the list and fetch any mail on accounts that are requesting it */ while( curpop ) { //if( (curpop -> flags & CHECK_WITH_ALL) && (curpop->type != IMAP) ) if( (curpop -> flags & CHECK_WITH_ALL) ) { if (curpop->type == POP3) { /* If we are supposed to process this account, do so, forking * a child process. Once we return here, having forked, wait * for it to finish before we continue. Otherwise, we'll wind * up with lots of concurrent account activity. */#ifdef DEBUG printf( "****>Forking receiving on account #%d from %d.\n", curpop -> id, getpid() ) ;#endif /* Make sure everyone knows what account we are on */ snum = disassemble_long( (unsigned long)curpop -> id ) ;#ifdef DEBUG printf( "****>ANNOUNCING ACCOUNT #%d from %d.\n", curpop -> id, getpid() ) ;#endif pipe_parent_stat_put( CURACCOUNT, snum, 4 ) ; free( snum ) ; /* Now, got get the messages */ pid = fork_receive_message1( curpop -> id, 0 ) ;#ifdef DEBUG printf( "****>Waiting on child process (forked %d) on account #%d.\n", pid, curpop -> id ) ;#endif /* Wait for the child to finish. Once it does, reset the value and let everyone know */ waitpid( pid, &childStat, 0 ) ; if( WIFSIGNALED( childStat ) ) { printf( "**********Child died because of %d.\n", WTERMSIG(childStat) ) ; /* * Test to see if this is a SIGKILL. If it is, someone doesn't want us to continue! * We'll exit with a 1 to let everyone know we've been harshly talked to. ;P~ */ if( WTERMSIG(childStat) == 9 ) _exit( 1 ) ; else { /* * If we are here, something bad happened which caused the child to die. * As such, we'll notify the parent that this happened via a DONE message. This * will prevent the parent from hanging on child that would otherwise never report * in. */#ifdef DEBUG printf( "[Dead Child Process]****>ANNOUNCING DONE\n" ) ;#endif } } #ifdef DEBUG else printf( "Child on account #%d exited normally.\n", curpop -> id ) ;#endif } } if (id) { curpop = NULL; } else { curpop = curpop -> next ; } }#ifdef DEBUG printf( "****>ANNOUNCING DONE\n" ) ;#endif pipe_parent_stat_put( DONE, "", 0 ) ; /* Okay, since all accounts have been serviced, let's kill exit this one */#ifdef DEBUG printf( "Returning from fork_receive_messages() since all accounts have been processed on pid %d\n", getpid() ) ;#endif _exit( 0 ) ; } else { /* Since we are the parent, let's wait on child (the above fork) to finish elsewhere, this * way, we don't get bunches of zombies...brains.... */ tm_globs -> pid = pid ; }#ifdef DEBUG printf( "Child process has been created to monitor background receiving...\n" ) ;#endif return ;}#ifdef DEBUG#undef DEBUGFORK#define DEBUGFORK 0#endifint fork_receive_message1( int popid, int announce ) { int pid=0, newmsgs=0, count=0, error=0; char *snum, *msg; PopAccount *curpop ; MAILSTREAM *stream = NULL ; int loggedIn ; int index ;#if DEBUGFORK > 0 int debugger ;#endif /* Get the current account record */ curpop = seek_popaccount( popid ) ; /* Now, make sure we only have a single connection per account */ if( curpop -> pid < 1 ) { /* Now, fork and let the messaging session run in the backgorund */ if( ( pid = fork() ) == 0 ) {#if DEBUGFORK > 0 /* Here for debugging only - this requires the debugger to change the value!!!! */ debugger = 1 ; while( debugger ) { printf( "Waiting on the debugger to save me on pid #%d in fork_receive_message1().\n", getpid() ) ; sleep( 1 ) ; }#endif /* Locate the current account info and create a MAIL stream for it */ loggedIn = 0 ; /* Now that we have the correct account, send it to the parent process */ if( announce ) {#if DEBUG > 5 printf( "Sending 'CURACCOUNT' to parent with id = %d.\n", curpop -> id ) ;#endif snum = disassemble_long( (unsigned long)curpop -> id ) ; if( announce ) pipe_parent_stat_put( CURACCOUNT, snum, 4 ) ; free( snum ) ; } pid = getpid() ;#ifdef DEBUG printf( "****>ANNOUNCING CURPID %d from %d.\n", pid, curpop -> id ) ;#endif snum = disassemble_long( (unsigned long)pid ) ; pipe_parent_stat_put( CURPID, snum, 4 ) ; free( snum ) ; /* Now, figure out how many new messages we have while we are logging into the account */ newmsgs = new_pop3_login( &stream, curpop -> id ) ;#if DEBUG > 3 printf( "Looks like we logged in and have %d new messages that need attention.\n", newmsgs ) ;#endif /* Make sure we have messages to process, if not, report the error */ snum = disassemble_long( (unsigned long)newmsgs ) ; if( newmsgs < 0 ) { pipe_parent_stat_put( PIPEERROR, snum, 4 ) ; free( snum ) ; pipe_data_put( OOOREAD, "", 0 ) ;#if DEBUG > 4 printf( "Requesting an Out Of Order Read.\n" ) ;#endif /* Log out if we have an odd error except when the connection * has already been closed, we don't know the host, or CONNREF */ if( (newmsgs != CONNREF) && (newmsgs != CONNCLOSED) && (newmsgs != UNKNOWNHOST) ) {#ifdef DEBUG printf( "calling logout in %d.\n", getpid() ) ;#endif if( loggedIn ) { new_pop3_logout( curpop -> id, stream ) ; loggedIn = 0 ; } } } else { /* Okay, this means we have messages to process */ pipe_parent_stat_put( NEWMESSAGES, snum, 4 ) ; free( snum ) ; /* Now that we know we have messages, let's fetch them! */ loggedIn = 1 ; index = curpop -> popcmsg ; /* Remember, msg numbers are base 1 and not base 0 */ for( count = 1 ; count <= newmsgs ; count++ ) {#ifdef DMALLOC dmalloc_verify( 0 ) ;#endif /* If we are deleting messages, we need to fetch all of them */ if( curpop -> flags & DELETEFROMSERVER ) { msg = new_pop3_get_message( curpop -> id, count, &error, stream ) ; } else { msg = new_pop3_get_message( curpop -> id, (index + count), &error, stream ) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -