SO_PUBLIC void Thread_InterruptAndJoin(struct Thread *thread) { ASSERT (thread != NULL); Thread_Stop(thread); Thread_Interrupt(thread); Thread_Join(thread); }
GF_EXPORT void gf_th_del(GF_Thread *t) { Thread_Stop(t, 0); #ifndef GPAC_DISABLE_LOG gf_free(t->log_name); #endif gf_free(t); }
SO_PUBLIC void Thread_Interrupt(struct Thread *thread) { ASSERT (thread != NULL); Thread_Stop(thread); #ifdef _MSC_VER //UNIMPLEMENTED(); #else //_MSC_VER pthread_kill(thread->iThread, SIGUSR1); #endif //_MSC_VER }
TEST_END //=========================================================================== TEST(ut_thread_stop) { // Test point - stop and restart a Thread_t Thread_Stop( &stThread1 ); Thread_Sleep(10); Thread_Start( &stThread1 ); // Poke the Thread_t using a Semaphore_t, verify it's still responding Semaphore_Post( &stSem2 ); Semaphore_TimedPend( &stSem1, 10 ); EXPECT_FALSE( Thread_GetExpired( Scheduler_GetCurrentThread() ) ); }
void gf_th_del(GF_Thread *t) { Thread_Stop(t, 0); #ifdef WIN32 // if (t->threadH) CloseHandle(t->threadH); #else /* It is necessary to free pthread handle */ if (t->threadH) pthread_detach(t->threadH); t->threadH = 0; #endif #ifndef GPAC_DISABLE_LOG gf_free(t->log_name); log_del_thread(t); #endif gf_free(t); }
GF_EXPORT void gf_th_stop(GF_Thread *t) { Thread_Stop(t, 0); }
GF_Err gf_th_run(GF_Thread *t, u32 (*Run)(void *param), void *param) { #ifdef WIN32 DWORD id; #else pthread_attr_t att; #endif if (!t || t->Run || t->_signal) return GF_BAD_PARAM; t->Run = Run; t->args = param; t->_signal = gf_sema_new(1, 0); #ifdef WIN32 t->threadH = CreateThread(NULL, t->stackSize, &(RunThread), (void *)t, 0, &id); if (t->threadH == NULL) { #else if ( pthread_attr_init(&att) != 0 ) return GF_IO_ERR; pthread_attr_setdetachstate(&att, PTHREAD_CREATE_JOINABLE); if ( pthread_create(&t->threadH, &att, RunThread, t) != 0 ) { #endif t->status = GF_THREAD_STATUS_DEAD; return GF_IO_ERR; } /*wait for the child function to call us - do NOT return before, otherwise the thread status would be unknown*/ gf_sema_wait(t->_signal); gf_sema_del(t->_signal); t->_signal = NULL; return GF_OK; } /* Stops a thread. If Destroy is not 0, thread is destroyed DANGEROUS as no cleanup */ void Thread_Stop(GF_Thread *t, Bool Destroy) { if (gf_th_status(t) == GF_THREAD_STATUS_RUN) { #ifdef WIN32 if (Destroy) { DWORD dw = 1; BOOL ret = TerminateThread(t->threadH, dw); if (!ret) { DWORD err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Thread %s] Couldn't stop thread ID 0x%08x, error code %d\n", t->log_name, t->id, err)); } t->threadH = NULL; } else { WaitForSingleObject(t->threadH, INFINITE); } #else if (Destroy) { #ifdef GPAC_ANDROID if (pthread_kill(t->threadH, SIGQUIT)) #else if (pthread_cancel(t->threadH)) #endif GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Thread %s] Couldn't kill thread ID 0x%08x\n", t->log_name, t->id)); t->threadH = 0; } else { /*gracefully wait for Run to finish*/ if (pthread_join(t->threadH, NULL)) GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Thread %s] pthread_join() returned an error with thread ID 0x%08x\n", t->log_name, t->id)); } #endif } t->status = GF_THREAD_STATUS_DEAD; } void gf_th_stop(GF_Thread *t) { Thread_Stop(t, 0); }
TEST_END //=========================================================================== TEST(ut_quanta) { K_ULONG ulAvg; K_ULONG ulMax; K_ULONG ulMin; K_ULONG ulRange; // Create three Thread_ts that only increment counters - similar to the // previous test. However, modify the Thread_t quanta such that each Thread_t // will get a different proportion of the CPU cycles. Thread_Init( &stThread1, aucStack1, TEST_STACK_SIZE, 1, RR_EntryPoint, (void*)&ulRR1); Thread_Init( &stThread2, aucStack2, TEST_STACK_SIZE, 1, RR_EntryPoint, (void*)&ulRR2); Thread_Init( &stThread3, aucStack3, TEST_STACK_SIZE, 1, RR_EntryPoint, (void*)&ulRR3); ulRR1 = 0; ulRR2 = 0; ulRR3 = 0; // Adjust Thread_t priority before starting test Thread_ts to ensure // they all start at the same time (when we hit the 1 second sleep) Thread_SetPriority( Scheduler_GetCurrentThread(), 2); // Set a different execution quanta for each Thread_t Thread_SetQuantum( &stThread1, 3); Thread_SetQuantum( &stThread2, 6); Thread_SetQuantum( &stThread3, 9); Thread_Start( &stThread1 ); Thread_Start( &stThread2 ); Thread_Start( &stThread3 ); Thread_Sleep(1800); // When the sleep ends, this will preempt the Thread_t in progress, // allowing us to stop them, and drop priority. Thread_Stop( &stThread1 ); Thread_Stop( &stThread2 ); Thread_Stop( &stThread3 ); Thread_SetPriority( Scheduler_GetCurrentThread(), 1); // Test point - make sure that Q3 > Q2 > Q1 EXPECT_GT( ulRR2, ulRR1 ); EXPECT_GT( ulRR3, ulRR2 ); // scale the counters relative to the largest value, and compare. ulRR1 *= 3; ulRR2 *= 3; ulRR2 = (ulRR2 + 1) / 2; // After scaling, they should be nearly identical (well, stose at least) if (ulRR1 > ulRR2) { ulMax = ulRR1; } else { ulMax = ulRR2; } if (ulMax < ulRR3) { ulMax = ulRR3; } if (ulRR1 < ulRR2) { ulMin = ulRR1; } else { ulMin = ulRR2; } if (ulMin > ulRR3) { ulMin = ulRR3; } ulRange = ulMax - ulMin; ulAvg = (ulRR1 + ulRR2 + ulRR3) / 3; #if KERNEL_TIMERS_TICKLESS // Max-Min delta should not exceed 5% of average for this test EXPECT_LT( ulRange, ulAvg / 20); #else // Max-Min delta should not exceed 20% of average for this test -- tick-based timers // are coarse, and prone to Thread_t preference due to phase. EXPECT_LT( ulRange, ulAvg / 5); #endif // Make sure none of the component values are 0 EXPECT_FAIL_EQUALS( ulRR1, 0 ); EXPECT_FAIL_EQUALS( ulRR2, 0 ); EXPECT_FAIL_EQUALS( ulRR3, 0 ); }
void TH_Delete(M4Thread *t) { Thread_Stop(t, 0); free(t); }
void TH_Stop(M4Thread *t) { Thread_Stop(t, 0); }