BOOL StopGCThread ( void *Ptr ) { int err; Slot_Mgr_Shr_t *MemPtr = (Slot_Mgr_Shr_t *) Ptr; void *Status; if ( ! ThreadRunning ) { DbgLog(DL0,"StopGCThread was called when the garbage collection thread was not running"); return FALSE; } DbgLog(DL0, "StopGCThread: tid %d is stopping the garbage collection thread (tid %d)", pthread_self(), GCThread); /* Cause the GC thread to be cancelled */ if ( ( err = pthread_cancel(GCThread)) != 0 ) { DbgLog(DL0,"StopGCThread: pthread_cancel returned %s (%d; %#x)", SysConst(err), err, err ); return FALSE; } /* Synchronize with the GC thread (aka: wait for it to terminate) */ if ( (err = pthread_join ( GCThread, &Status ) ) != 0 ) { DbgLog(DL0,"StopGCThread: pthread_join returned %s (%d; %#x)", SysConst(err), err, err ); return FALSE; } if ( Status != PTHREAD_CANCELED ) { DbgLog(DL0,"Hmm. Thread was cancelled, but didn't return the appropriate return status"); } ThreadRunning = FALSE; return TRUE; }
BOOL StartGCThread ( Slot_Mgr_Shr_t *MemPtr ) { int err; #if !(THREADED) return TRUE; #endif if ( ThreadRunning ) { DbgLog (DL0, "StartGCThread: Thread already running."); return FALSE; } if ( ( err = pthread_create( &GCThread, NULL, GCMain, ((void *)MemPtr) ) ) != 0 ) { DbgLog(DL0,"StartGCThread: pthread_create returned %s (%d; %#x)", SysConst(err), err, err ); return FALSE; } ThreadRunning = TRUE; #ifdef DEV // Only development builds LogLog ( "StartGCThread: garbage collection thread started as ID %d (%#x) by ID %d (%#x)", GCThread, GCThread, pthread_self(), pthread_self() ); #endif return TRUE; }
BOOL SaveStartupDirectory ( char *Arg0 ) { unsigned int Err; char cwd[PATH_MAX+1]; char arg[PATH_MAX+1]; char *dname = NULL; ASSERT( Arg0 != NULL ); if ( getcwd ( cwd, PathSize ) == NULL ) { Err = errno; DbgLog(DL0,"SaveStartupDirectory: getcwd returned %s (%d)", SysConst(Err), Err); return FALSE; } /* Free previous copy */ if ( StartDir != NULL ) { free(StartDir); StartDir = NULL; } /* Allocate memory */ if ( (StartDir = calloc ( PathSize, sizeof(char) ) ) == NULL ) { Err = errno; DbgLog(DL0,"SaveStartupDirectory: Unable to allocate %d bytes of memory for storage of the CWD. %s (%d)\n", SysConst(Err), Err ); exit(1); } /* If Arg0 contains a /, then dirname(Arg0) is appended to cwd */ /* This will handle the case where you were in directory foo, and started the daemon * as bar/daemon */ /* FIXME: This will not work properly if the daemon was found by searching the PATH */ /* Make a local copy of the string because dirname() modifies it's arguments */ strcpy( arg, Arg0 ); dname = dirname ( arg ); /* note that dirname("daemon") and dirname("./daemon") will return "." */ if ( strcmp( dname, "." ) != 0 ) { /* there's a / in it... */ sprintf(StartDir, "%s/%s", cwd, dname); } else { sprintf(StartDir, "%s", cwd); } return TRUE; }
BOOL IsValidProcessEntry ( pid_t_64 pid, time_t_64 RegTime ) { int Err; int valid; proc_t *p; proc_t procstore; /* If kill(pid, 0) returns -1 and errno/Err = ESRCH, the pid doesn't exist */ if ( kill(pid, 0) == -1 ) { Err = errno; if ( Err == ESRCH ) { /* The process was not found */ DbgLog(DL3, "IsValidProcessEntry: PID %d was not found in the process table (kill() returned %s)", pid, SysConst(Err) ); return FALSE; } else { /* some other error occurred */ DbgLog(DL3, "IsValidProcessEntry: kill() returned %s (%d; %#x)", SysConst(Err), Err, Err); return FALSE; } } /* end if kill */ /* Okay, the process exists, now we see if it's really ours */ #ifdef ALLOCATE p = (proc_t *)malloc(sizeof(proc_t)); #else p = &procstore; memset(p, 0, sizeof(proc_t)); #endif if( !(valid = Stat2Proc( (int)pid, p )) ) return FALSE; if ( p->pid == pid ) { if ( RegTime >= p->start_time ) { // checking for matching start times return TRUE; } else { /* p->start_time contains the time at which the process began ?? (22nd element in /proc/<pid>/stat file) */ DbgLog(DL1, "IsValidProcessEntry: PID %d started at %lu; registered at %ld", pid, p->start_time, RegTime); DbgLog(DL4, "IsValidProcessEntry: PID Returned %d flags at %#x; state at %#x", p->pid, p->flags, p->state); } } return FALSE; }
BOOL IsValidProcessEntry ( pid_t pid, time_t RegTime ) { #endif #ifdef PKCS64 pid_t Index = (pid_t)pid; #else pid_t Index = pid; #endif struct procsinfo64 ProcInfo[1]; /* getprocs wants arrays; I'm just being anal; I know it's stupid to declare an array of 1 element */ struct fdsinfo_2000 FileInfo[1]; /* if you pass a struct fdsinfo, you get a core dump */ int Count = 1; int Err; /* Note that Index is modified by this call; use pid to see what process id we're looking for afterwards */ if ( getprocs ( &(ProcInfo[0]), sizeof(ProcInfo), NULL, NULL, &Index, Count ) != Count ) { Err = errno; if ( Err == EINVAL ) { /* The process was not found */ DbgLog(DL3, "IsValidProcessEntry: PID %d was not found in the process table (getprocs() returned %s)", pid, SysConst(Err) ); return FALSE; } else { /* some other error occurred */ DbgLog(DL3,"IsValidProcessEntry: getprocs() returned %s (%d; %#x)", SysConst(Err), Err, Err); return FALSE; } } /* end if getprocs */ /* Okay, the process exists, now we see if it's really ours */ if ( ProcInfo[0].pi_pid == pid) { if ( RegTime >= ProcInfo[0].pi_start ) { return TRUE; } else { /* ProcInfo[0].pi_start contains the time at which the process began */ DbgLog(DL1, "IsValidProcessEntry: PID %d started at %lld; registered at %ld", pid, ProcInfo[0].pi_start, RegTime); DbgLog(DL4, "IsValidProcessEntry: PID Returned %d flags at %#x; state at %#x index %d", ProcInfo[0].pi_pid, ProcInfo[0].pi_flags, ProcInfo[0].pi_state,Index); } } return FALSE; }
BOOL CheckForGarbage ( Slot_Mgr_Shr_t *MemPtr ) { int SlotIndex; int ProcIndex; int Err; BOOL ValidPid; ASSERT( MemPtr != NULL_PTR ); #ifdef DEV DbgLog(DL5, "Thread %d is checking for garbage", pthread_self()); #endif /* DEV */ #ifdef DEV DbgLog (DL5, "Garbage collection attempting global shared memory lock"); #endif /* DEV */ /* Grab the global Shared mem mutex since we might modify global_session_count */ #ifdef PKCS64 Err = msem_lock(&(MemPtr->slt_mutex),0); #else Err = pthread_mutex_lock ( &(MemPtr->slt_mutex) ); #endif if ( Err != 0 ) { DbgLog (DL0, "Garbage collection: Locking attempt for global shmem mutex returned %s", SysConst(Err) ); return FALSE; } #ifdef DEV DbgLog ( DL5, "Garbage collection: Got global shared memory lock"); #endif /* DEV */ for ( ProcIndex = 0; ProcIndex < NUMBER_PROCESSES_ALLOWED; ProcIndex++ ) { #ifdef PKCS64 Slot_Mgr_Proc_t_64 *pProc = &(MemPtr->proc_table[ProcIndex]); #else Slot_Mgr_Proc_t *pProc = &(MemPtr->proc_table[ProcIndex]); #endif ASSERT(pProc != NULL_PTR); if ( ! (pProc->inuse) ) { continue; } ValidPid = ( (IsValidProcessEntry ( pProc->proc_id, pProc->reg_time )) && (pProc->proc_id != 0) ); if ( ( pProc->inuse ) && (! ValidPid ) ) { #ifdef DEV DbgLog(DL1, "Garbage collection routine found bad entry for pid %d (Index: %d); removing from table", pProc->proc_id, ProcIndex ); #endif /* DEV */ /* */ /* Clean up session counts */ /* */ for ( SlotIndex = 0; SlotIndex < NUMBER_SLOTS_MANAGED; SlotIndex++ ) { #ifdef PKCS64 unsigned int *pGlobalSessions = &(MemPtr->slot_info[SlotIndex].global_sessions); unsigned int *pProcSessions = &(pProc->slot_session_count[SlotIndex]); #else int *pGlobalSessions = &(MemPtr->slot_info[SlotIndex].global_sessions); int *pProcSessions = &(pProc->slot_session_count[SlotIndex]); #endif if ( *pProcSessions > 0 ) { #ifdef DEV DbgLog ( DL2, "GC: Invalid pid (%d) is holding %d sessions open on slot %d. Global session count for this slot is %d", pProc->proc_id, *pProcSessions, SlotIndex, *pGlobalSessions ); #endif /* DEV */ if ( *pProcSessions > *pGlobalSessions ) { #ifdef DEV WarnLog ( "Garbage Collection: Illegal values in table for defunct process"); DbgLog ( DL0, "Garbage collection: A process ( Index: %d, pid: %d ) showed %d sessions open on slot %s, but the global count for this slot is only %d", ProcIndex, pProc->proc_id, *pProcSessions, SlotIndex, *pGlobalSessions ); #endif /* DEV */ *pGlobalSessions = 0; } else { *pGlobalSessions -= *pProcSessions; } *pProcSessions = 0; } /* end if *pProcSessions */ } /* end for SlotIndex */ /* */ /* NULL out everything except the mutex */ /* */ #if PER_PROCESS_MUTEXES /* Grab the mutex for this proc's shared memory data structure */ #ifdef PKCS64 Err = msem_lock(&(pProc->proc_mutex),MSEM_IF_NOWAIT); #else Err = pthread_mutex_trylock( &(pProc->proc_mutex) ); #endif if ( ( Err != 0 ) ) { /* We didn't get the lock! */ /* Attempting to destroy a locked mutex results in undefined behavior */ /* http://techlib.austin.ibm.com/techlib/manuals/adoclib/libs/basetrf1/pthreads.htm */ DbgLog (DL0,"Unable to get per-process mutex for pid %d (%s) - skipping", pProc->proc_id, SysConst( Err ) ); /* The exit routine will figure out that this is an invalid process entry (by calling IsValidProcessEntry()), and won't prevent the slotd from exiting because of this entry. */ continue; } #endif /* PER_PROCESS_MUTEXES */ memset( &(pProc->inuse), '\0', sizeof(pProc->inuse) ); memset( &(pProc->proc_id), '\0', sizeof(pProc->proc_id) ); memset( &(pProc->slotmap), '\0', sizeof(pProc->slotmap) ); memset( &(pProc->blocking), '\0', sizeof(pProc->blocking )); memset( &(pProc->error), '\0', sizeof(pProc->error) ); memset( &(pProc->slot_session_count), '\0', sizeof(pProc->slot_session_count) ); memset( &(pProc->reg_time), '\0', sizeof(pProc->reg_time) ); } /* end if inuse && ValidPid */ #if PER_PROCESS_MUTEXES #ifdef PKCS64 msem_unlock(&(pProc->proc_mutex),0) #else pthread_mutex_unlock( &(pProc->proc_mutex)); #endif #endif /* PER_PROCESS_MUTEXES */ } /* end for ProcIndex */ #ifdef PKCS64 msem_unlock(&(MemPtr->slt_mutex),0); #else pthread_mutex_unlock ( &(MemPtr->slt_mutex) ); #endif DbgLog ( DL5, "Garbage collection: Released global shared memory lock"); return TRUE; }
BOOL CheckForGarbage ( Slot_Mgr_Shr_t *MemPtr ) { int SlotIndex; int ProcIndex; int Err; BOOL ValidPid; ASSERT( MemPtr != NULL_PTR ); #ifdef DEV DbgLog(DL5, "Thread %d is checking for garbage", pthread_self()); #endif /* DEV */ #ifdef DEV DbgLog (DL5, "Garbage collection attempting global shared memory lock"); #endif /* DEV */ /* Grab the global Shared mem mutex since we might modify global_session_count */ Err = XProcLock(); if ( Err != TRUE ) { DbgLog (DL0, "Garbage collection: Locking attempt for global shmem mutex returned %s", SysConst(Err) ); return FALSE; } #ifdef DEV DbgLog ( DL5, "Garbage collection: Got global shared memory lock"); #endif /* DEV */ for ( ProcIndex = 0; ProcIndex < NUMBER_PROCESSES_ALLOWED; ProcIndex++ ) { Slot_Mgr_Proc_t_64 *pProc = &(MemPtr->proc_table[ProcIndex]); ASSERT(pProc != NULL_PTR); if ( ! (pProc->inuse) ) { continue; } ValidPid = ( (IsValidProcessEntry ( pProc->proc_id, pProc->reg_time )) && (pProc->proc_id != 0) ); if ( ( pProc->inuse ) && (! ValidPid ) ) { #ifdef DEV DbgLog(DL1, "Garbage collection routine found bad entry for pid %d (Index: %d); removing from table", pProc->proc_id, ProcIndex ); #endif /* DEV */ /* */ /* Clean up session counts */ /* */ for ( SlotIndex = 0; SlotIndex < NUMBER_SLOTS_MANAGED; SlotIndex++ ) { unsigned int *pGlobalSessions = &(MemPtr->slot_global_sessions[SlotIndex]); unsigned int *pProcSessions = &(pProc->slot_session_count[SlotIndex]); if ( *pProcSessions > 0 ) { #ifdef DEV DbgLog ( DL2, "GC: Invalid pid (%d) is holding %d sessions open on slot %d. Global session count for this slot is %d", pProc->proc_id, *pProcSessions, SlotIndex, *pGlobalSessions ); #endif /* DEV */ if ( *pProcSessions > *pGlobalSessions ) { #ifdef DEV WarnLog ( "Garbage Collection: Illegal values in table for defunct process"); DbgLog ( DL0, "Garbage collection: A process ( Index: %d, pid: %d ) showed %d sessions open on slot %s, but the global count for this slot is only %d", ProcIndex, pProc->proc_id, *pProcSessions, SlotIndex, *pGlobalSessions ); #endif /* DEV */ *pGlobalSessions = 0; } else { *pGlobalSessions -= *pProcSessions; } *pProcSessions = 0; } /* end if *pProcSessions */ } /* end for SlotIndex */ /* */ /* NULL out everything except the mutex */ /* */ memset( &(pProc->inuse), '\0', sizeof(pProc->inuse) ); memset( &(pProc->proc_id), '\0', sizeof(pProc->proc_id) ); memset( &(pProc->slotmap), '\0', sizeof(pProc->slotmap) ); memset( &(pProc->blocking), '\0', sizeof(pProc->blocking )); memset( &(pProc->error), '\0', sizeof(pProc->error) ); memset( &(pProc->slot_session_count), '\0', sizeof(pProc->slot_session_count) ); memset( &(pProc->reg_time), '\0', sizeof(pProc->reg_time) ); } /* end if inuse && ValidPid */ } /* end for ProcIndex */ XProcUnLock(); DbgLog ( DL5, "Garbage collection: Released global shared memory lock"); return TRUE; }
BOOL DestroyConditionVariables ( void ) { int err; if ( (err = pthread_mutex_destroy ( &(shmp->shmem_cv_mutex) ) ) != 0 ) { DbgLog(DL0,"DestroyConditionVariables: pthread_mutex_destroy returned %s (%d; %#x)\n", SysConst(err), err, err); return FALSE; } if ( (err = pthread_cond_destroy( &(shmp->shmem_cv) ) ) != 0 ) { DbgLog(DL0,"DestroyConditionVariables: pthread_cond_destroy returned %s (%d; %#x)\n", SysConst(err), err, err); return FALSE; } if ( (err = pthread_condattr_destroy( &(shmp->shmem_cv_attr) ) ) != 0 ) { DbgLog(DL0,"DestroyConditionVariables: pthread_condattr_destroy returned %s (%d; %#x)\n", SysConst(err), err, err); return FALSE; } return TRUE; }
BOOL InitializeConditionVariables ( void ) { int err; if ( (err = pthread_condattr_init( &(shmp->shmem_cv_attr) ) ) != 0 ) { DbgLog(DL0,"InitializeConditionVariables: pthread_condattr_init returned %s (%d; %#x)\n", SysConst(err), err, err); return FALSE; } if ( (err = pthread_cond_init( &(shmp->shmem_cv), &(shmp->shmem_cv_attr) ) ) != 0 ) { DbgLog(DL0,"InitializeConditionVariables: pthread_cond_init returned %s (%d; %#x)\n", SysConst(err), err, err); return FALSE; } if ( (err = pthread_mutex_init( &(shmp->shmem_cv_mutex), &mtxattr ) ) != 0 ) { DbgLog(DL0,"InitializeConditionVariables: pthread_mutex_init returned %s (%d; %#x)\n", SysConst(err), err, err); return FALSE; } return TRUE; }