📄 garbage.c
字号:
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;}/********************************************************************************* * GCMain - * * The Garbage collection thread's main() * Basically, run until cancelled by another thread * *********************************************************************************/static void *GCMain ( void *Ptr) { int OrigCancelState; int OrigCancelType; int LastCancelState; int i; Slot_Mgr_Shr_t *MemPtr = (Slot_Mgr_Shr_t *) Ptr; ASSERT ( MemPtr != NULL ); /* setup */ /* Block the signals that go to the main thread */ /* FIXME: We probably want to make it so that signals go only to the main thread by default */ GCBlockSignals(); /* Make it so that we can only be cancelled when we reach a cancellation point */ /* cancellation points are listed here: http://techlib.austin.ibm.com/techlib/manuals/adoclib/aixprggd/genprogc/termthre.htm#D3A4499176manu */ /* PTHREAD_CANCEL_DEFERRED should be the default */ pthread_setcancelstate ( PTHREAD_CANCEL_ENABLE, &OrigCancelState ); pthread_setcanceltype ( PTHREAD_CANCEL_DEFERRED, &OrigCancelType ); /* push cleanup routines */ pthread_cleanup_push ( GCCancel, MemPtr ); while ( 1 ) { DbgLog(DL5, "Garbage collection running..."); /* Don't allow cancellations while mucking with shared memory or holding mutexes */ pthread_setcancelstate ( PTHREAD_CANCEL_DISABLE, &LastCancelState ); CheckForGarbage(MemPtr); /* re-enable cancellations */ pthread_setcancelstate ( PTHREAD_CANCEL_ENABLE, &LastCancelState ); /* Test for cancellation by the main thread */ pthread_testcancel(); DbgLog(DL5, "Garbage collection finished."); /* now we pause */ sleep(10); } /* end while 1 */ /* Yeah, yeah. Has to be here because some implementations use macros that have to be balanced */ pthread_cleanup_pop ( 0 ); /* return implicitly calls pthread_cancel() */ /* but it'll never really get executed; pthread_testcancel() implicitly calls pthread_exit() if there's a cancellation pending */ return NULL;}/********************************************************************************* * GCCancel - * * Cleanup routine called when Garbage collection thread exits/is cancelled * *********************************************************************************/static void GCCancel ( void *Ptr ) { Slot_Mgr_Shr_t *MemPtr = (Slot_Mgr_Shr_t *) Ptr; /* Yeah, yeah. Doesn't do anything, but I had plans */ DbgLog(DL3, "GCCancel: tid: %d running cleanup routine", pthread_self()); return;}/********************************************************************************* * CheckForGarbage - * * The routine that actually does cleanup * *********************************************************************************/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; }/********************************************************************************* * IsValidProcessEntry - * * Checks to see if the process identifed by pid is the same process * that registered with us * *********************************************************************************/#ifdef PKCS64BOOL IsValidProcessEntry ( pid_t_64 pid, time_t_64 RegTime ) {#elseBOOL 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;}#endif // NO Garbage
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -