abyss_thread_fork.c

00001 /******************************************************************************
00002 **
00003 ** thread_fork.c
00004 **
00005 ** This file is part of the ABYSS Web server project.
00006 **
00007 ** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.
00008 ** All rights reserved.
00009 **
00010 ** Redistribution and use in source and binary forms, with or without
00011 ** modification, are permitted provided that the following conditions
00012 ** are met:
00013 ** 1. Redistributions of source code must retain the above copyright
00014 **    notice, this list of conditions and the following disclaimer.
00015 ** 2. Redistributions in binary form must reproduce the above copyright
00016 **    notice, this list of conditions and the following disclaimer in the
00017 **    documentation and/or other materials provided with the distribution.
00018 ** 3. The name of the author may not be used to endorse or promote products
00019 **    derived from this software without specific prior written permission.
00020 ** 
00021 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00022 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00025 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00027 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00028 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031 ** SUCH DAMAGE.
00032 **
00033 *******************************************************************************/
00034 
00035 #include <sys/types.h>
00036 #include <stdlib.h>
00037 #include <unistd.h>
00038 #include <string.h>
00039 #include <errno.h>
00040 #include <sys/wait.h>
00041 #include <signal.h>
00042 
00043 #include <xmlrpc-c/config.h>
00044 #include "abyss_xmlrpc_int.h"
00045 #include <xmlrpc-c/abyss.h>
00046 
00047 #include "abyss_mallocvar.h"
00048 #include "abyss_thread.h"
00049 
00050 
00051 static void
00052 blockSignalClass(int        const signalClass,
00053                  sigset_t * const oldBlockedSetP) {
00054 
00055     sigset_t newBlockedSet;
00056 
00057     sigemptyset(&newBlockedSet);
00058     sigaddset(&newBlockedSet, signalClass);
00059 
00060     sigprocmask(SIG_BLOCK, &newBlockedSet, oldBlockedSetP);
00061 }
00062 
00063 
00064 
00065 struct abyss_thread {
00066     struct abyss_thread * nextInPoolP;
00067     TThreadDoneFn * threadDone;
00068     void * userHandle;
00069     pid_t pid;
00070     abyss_bool useSigchld;
00071         /* This means that user is going to call ThreadHandleSigchld()
00072            when it gets a death of a child signal for this process.  If
00073            false, he's going to leave us in the dark, so we'll have to
00074            poll to know if the process is dead or not.
00075         */
00076 };
00077 
00078 
00079 /* Because signals are global, we need this global variable in order for
00080    the signal handler to figure out to what thread the signal belongs.
00081 */
00082 
00083 /* We use a singly linked list.  Every time we access it, we have to run
00084    the whole chain.  To make this scale up, we should replace it with
00085    a doubly linked list and some kind of index by PID.
00086 
00087    But large scale systems probably aren't using fork threads anyway.
00088 */
00089 
00090 static struct {
00091     struct abyss_thread * firstP;
00092 } ThreadPool;
00093    
00094 
00095 
00096 void
00097 ThreadPoolInit(void) {
00098 
00099     ThreadPool.firstP = NULL;
00100 }
00101 
00102 
00103 
00104 static struct abyss_thread *
00105 findThread(pid_t const pid) {
00106 
00107     struct abyss_thread * p;
00108 
00109     for (p = ThreadPool.firstP; p && p->pid != pid; p = p->nextInPoolP);
00110     
00111     return p;
00112 }
00113 
00114 
00115 
00116 static void
00117 addToPool(struct abyss_thread * const threadP) {
00118 
00119     if (ThreadPool.firstP == NULL)
00120         ThreadPool.firstP = threadP;
00121     else {
00122         struct abyss_thread * p;
00123 
00124         for (p = ThreadPool.firstP; p->nextInPoolP; p = p->nextInPoolP);
00125 
00126         /* p points to the last thread in the list */
00127 
00128         p->nextInPoolP = threadP;
00129     }
00130 }
00131 
00132 
00133 
00134 static void
00135 removeFromPool(struct abyss_thread * const threadP) {
00136 
00137     if (threadP == ThreadPool.firstP)
00138         ThreadPool.firstP = threadP->nextInPoolP;
00139     else {
00140         struct abyss_thread * p;
00141 
00142         for (p = ThreadPool.firstP;
00143              p && p->nextInPoolP != threadP;
00144              p = p->nextInPoolP);
00145         
00146         if (p)
00147             /* p points to thread right before the one we want to remove */
00148             p->nextInPoolP = threadP->nextInPoolP;
00149     }
00150 }
00151 
00152 
00153 
00154 void
00155 ThreadHandleSigchld(pid_t const pid) {
00156 /*----------------------------------------------------------------------------
00157    Handle a death of a child signal for process 'pid', which may be one
00158    of our threads.
00159 -----------------------------------------------------------------------------*/
00160     struct abyss_thread * const threadP = findThread(pid);
00161 
00162     if (threadP) {
00163         if (threadP->threadDone)
00164             threadP->threadDone(threadP->userHandle);
00165         threadP->pid = 0;
00166     }
00167     /* Note that threadDone might free *threadP */
00168 }
00169 
00170 
00171 
00172 void
00173 ThreadUpdateStatus(TThread * const threadP) {
00174 
00175     if (!threadP->useSigchld) {
00176         if (threadP->pid) {
00177             if (kill(threadP->pid, 0) != 0) {
00178                 if (threadP->threadDone)
00179                     threadP->threadDone(threadP->userHandle);
00180                 threadP->pid = 0;
00181             }
00182         }
00183     }
00184 }
00185 
00186 
00187 
00188 void
00189 ThreadCreate(TThread **      const threadPP,
00190              void *          const userHandle,
00191              TThreadProc   * const func,
00192              TThreadDoneFn * const threadDone,
00193              abyss_bool      const useSigchld,
00194              const char **   const errorP) {
00195     
00196     TThread * threadP;
00197 
00198     MALLOCVAR(threadP);
00199     if (threadP == NULL)
00200         xmlrpc_asprintf(errorP,
00201                         "Can't allocate memory for thread descriptor.");
00202     else {
00203         sigset_t oldBlockedSet;
00204         pid_t rc;
00205 
00206         threadP->nextInPoolP = NULL;
00207         threadP->threadDone  = threadDone;
00208         threadP->userHandle  = userHandle;
00209         threadP->useSigchld  = useSigchld;
00210         threadP->pid         = 0;
00211 
00212         /* We have to be sure we don't get the SIGCHLD for this child's
00213            death until the child is properly registered in the thread pool
00214            so that the handler will know who he is.
00215         */
00216         blockSignalClass(SIGCHLD, &oldBlockedSet);
00217 
00218         rc = fork();
00219         
00220         if (rc < 0)
00221             xmlrpc_asprintf(errorP, "fork() failed, errno=%d (%s)",
00222                             errno, strerror(errno));
00223         else if (rc == 0) {
00224             /* This is the child */
00225             (*func)(userHandle);
00226             exit(0);
00227         } else {
00228             /* This is the parent */
00229             threadP->pid = rc;
00230 
00231             addToPool(threadP);
00232 
00233             sigprocmask(SIG_SETMASK, &oldBlockedSet, NULL);  /* restore */
00234 
00235             *errorP = NULL;
00236             *threadPP = threadP;
00237         }
00238         if (*errorP) {
00239             removeFromPool(threadP);
00240             free(threadP);
00241         }
00242     }
00243 }
00244 
00245 
00246 
00247 abyss_bool
00248 ThreadRun(TThread * const threadP ATTR_UNUSED) {
00249     return TRUE;    
00250 }
00251 
00252 
00253 
00254 abyss_bool
00255 ThreadStop(TThread * const threadP ATTR_UNUSED) {
00256     return TRUE;
00257 }
00258 
00259 
00260 
00261 abyss_bool
00262 ThreadKill(TThread * const threadP ATTR_UNUSED) {
00263     return TRUE;
00264 }
00265 
00266 
00267 
00268 void
00269 ThreadWaitAndRelease(TThread * const threadP) {
00270 
00271     if (threadP->pid) {
00272         int exitStatus;
00273 
00274         waitpid(threadP->pid, &exitStatus, 0);
00275 
00276         threadP->threadDone(threadP->userHandle);
00277 
00278         threadP->pid = 0;
00279     }
00280     ThreadRelease(threadP);
00281 }
00282 
00283 
00284 
00285 void
00286 ThreadExit(int const retValue) {
00287 
00288     /* Note that the OS will automatically send a SIGCHLD signal to
00289        the parent process after we exit.  The handler for that signal
00290        will run threadDone in parent's context.  Alternatively, if
00291        the parent is set up for signals, the parent will eventually
00292        poll for the existence of our PID and call threadDone when he
00293        sees we've gone.
00294     */
00295 
00296     exit(retValue);
00297 }
00298 
00299 
00300 
00301 void
00302 ThreadRelease(TThread * const threadP) {
00303 
00304     removeFromPool(threadP);
00305     free(threadP);
00306 }
00307 
00308 
00309 
00310 abyss_bool
00311 ThreadForks(void) {
00312 
00313     return TRUE;
00314 }
00315 
00316 
00317 
00318 /*********************************************************************
00319 ** Mutex
00320 *********************************************************************/
00321 
00322 /* As two processes don't share memory, there is nothing to synchronize,
00323    so locking is a no-op.
00324 */
00325 
00326 abyss_bool
00327 MutexCreate(TMutex * const mutexP ATTR_UNUSED) {
00328     return TRUE;
00329 }
00330 
00331 
00332 
00333 abyss_bool
00334 MutexLock(TMutex * const mutexP ATTR_UNUSED) {
00335     return TRUE;
00336 }
00337 
00338 
00339 
00340 abyss_bool
00341 MutexUnlock(TMutex * const mutexP ATTR_UNUSED) {
00342     return TRUE;
00343 }
00344 
00345 
00346 
00347 abyss_bool
00348 MutexTryLock(TMutex * const mutexP ATTR_UNUSED) {
00349     return TRUE;
00350 }
00351 
00352 
00353 
00354 void
00355 MutexFree(TMutex * const mutexP ATTR_UNUSED) {
00356 
00357 }