/* * Stop all threads in the pool. */ void thread_pool_stop(void) { #ifndef WITH_GCD int i; int total_threads; THREAD_HANDLE *handle; THREAD_HANDLE *next; /* * Set pool stop flag. */ thread_pool.stop_flag = 1; /* * Wakeup all threads to make them see stop flag. */ total_threads = thread_pool.total_threads; for (i = 0; i != total_threads; i++) { sem_post(&thread_pool.semaphore); } /* * Join and free all threads. */ for (handle = thread_pool.head; handle; handle = next) { next = handle->next; pthread_join(handle->pthread_id, NULL); delete_thread(handle); } #endif }
int main() { #ifdef USE_DYNAMO dynamorio_app_init(); dynamorio_app_start(); #endif sleeptime.tv_sec = 0; sleeptime.tv_nsec = 10*1000*1000; /* 10ms */ child_exit = false; child_done = false; child = create_thread(run, NULL, &stack); assert(child > -1); /* waste some time */ nanosleep(&sleeptime, NULL); child_exit = true; /* we want deterministic printf ordering */ while (!child_done) nanosleep(&sleeptime, NULL); delete_thread(child, stack); #ifdef USE_DYNAMO dynamorio_app_stop(); dynamorio_app_exit(); #endif }
int main() { int i; sleeptime.tv_sec = 0; sleeptime.tv_nsec = 10 * 1000 * 1000; /* 10ms */ /* parent remains in own group. creates child who creates a thread group * and then exits them all */ for (i = 0; i < NUM_THREADS; i++) { child_started[i] = false; child_exit[i] = false; } child[0] = create_thread(run, (void *)(long)0, &stack[0], false); assert(child[0] > -1); /* wait for child to start rest of threads */ for (i = 0; i < NUM_THREADS; i++) { while (!child_started[i]) { /* waste some time: FIXME: should use futex */ nanosleep(&sleeptime, NULL); } } child_exit[0] = true; while (!child_done[0]) nanosleep(&sleeptime, NULL); delete_thread(child[0], stack[0]); for (i = 1; i < NUM_THREADS; i++) stack_free(stack[i], THREAD_STACK_SIZE); }
void thread2(void) { int i = -100; for(;i<0;) { printf("%s: count = %d\n",__func__,i++); yield(); } delete_thread(); assert(0); }
void thread1(void) { int i = 1; for(;i<100;) { printf("%s: count = %d\n",__func__,i++); yield(); } delete_thread(); printf("%s\n","delete_thread2"); assert(0); }
void test_thread(bool share_sighand) { /* First make a thread that shares signal handlers. */ child_exit = false; child_done = false; child = create_thread(run, NULL, &stack, share_sighand); assert(child > -1); /* waste some time */ nanosleep(&sleeptime, NULL); child_exit = true; /* we want deterministic printf ordering */ while (!child_done) nanosleep(&sleeptime, NULL); delete_thread(child, stack); }
static ptid_t fbsd_thread_wait (struct target_ops *ops, ptid_t ptid, struct target_waitstatus *ourstatus, int options) { struct target_ops *beneath = find_target_beneath (ops); ptid_t ret; long lwp; CORE_ADDR stop_pc; td_thrhandle_t th; td_thrinfo_t ti; ret = beneath->to_wait (beneath, ptid, ourstatus, options); if (GET_PID(ret) >= 0 && ourstatus->kind == TARGET_WAITKIND_STOPPED) { lwp = get_current_lwp (GET_PID(ret)); ret = thread_from_lwp (BUILD_LWP(lwp, GET_PID(ret)), &th, &ti); if (!in_thread_list(ret)) { /* * We have to enable event reporting for initial thread * which was not mapped before. */ attach_thread(ret, &th, &ti, 1); } if (ourstatus->value.sig == TARGET_SIGNAL_TRAP) check_event(ret); /* this is a hack, if an event won't cause gdb to stop, for example, SIGALRM, gdb resumes the process immediatly without setting inferior_ptid to the new thread returned here, this is a bug because inferior_ptid may already not exist there, and passing a non-existing thread to fbsd_thread_resume causes error. However, if the exiting thread is the currently selected thread, then that is handled later in handle_inferior_event(), and we must not delete the currently selected thread. */ if (!fbsd_thread_alive (ops, inferior_ptid) && !ptid_equal(inferior_ptid, ret)) { delete_thread (inferior_ptid); inferior_ptid = ret; } } return (ret); }
static void haiku_remove_thread(team_debug_info *teamDebugInfo, thread_id threadID) { thread_debug_info **info; for (info = &teamDebugInfo->threads; *info; info = &(*info)->next) { if ((*info)->thread == threadID) { thread_debug_info *foundInfo = *info; *info = foundInfo->next; if (foundInfo->last_event) xfree(foundInfo->last_event); xfree(foundInfo); // remove it from gdb's thread DB delete_thread(ptid_build(teamDebugInfo->team, 0, threadID)); return; } } }
void simple_thread(void) { int i, myID, sleep; myID = count; count ++; /* for the next thread * It is shared, do I need to lock??? A lock is not necessary. Yielding is collaborative. So cant be pre-empted at the middle */ for(i=myID; i<MAX;i++) { /* print something, sleep for a while and yield */ printf("I'm %s %d: Count=%d\n",__func__,myID,i); for(sleep=-COUNT(myID); sleep < COUNT(myID); sleep++); yield(); } delete_thread(); /* die */ assert(0); /* I should not be running */ }
int free_iothread(iothread_t* iothr) { int err; if (iothr->thread) { requeststop_iothread(iothr); (void) join_thread(iothr->thread); cancelall_iolist(&iothr->iolist); err = delete_thread(&iothr->thread); (void) PROCESS_testerrortimer(&s_iothread_errtimer, &err); if (err) goto ONERR; } return 0; ONERR: TRACEEXITFREE_ERRLOG(err); return err; }
int main() { sleeptime.tv_sec = 0; sleeptime.tv_nsec = 10*1000*1000; /* 10ms */ child_exit = false; child_done = false; child = create_thread(run, NULL, &stack); assert(child > -1); /* waste some time */ nanosleep(&sleeptime, NULL); child_exit = true; /* we want deterministic printf ordering */ while (!child_done) nanosleep(&sleeptime, NULL); delete_thread(child, stack); return 0; }
void main_loop() { char input[STRING_SIZE]; thread_t threads[MAX_THREADS_COUNT]; struct thread_args_t all_args[MAX_THREADS_COUNT]; int last_thread_id = -1; while (1) { fgets(input, STRING_SIZE, stdin); switch (input[0]) { case '+': add_thread(threads, all_args, ++last_thread_id); break; case '-': delete_thread(threads, all_args, &last_thread_id); break; case 'q': kill_all_threads(threads, all_args, last_thread_id); return; } } }
static ptid_t fbsd_thread_wait (ptid_t ptid, struct target_waitstatus *ourstatus) { ptid_t ret; long lwp; CORE_ADDR stop_pc; td_thrhandle_t th; td_thrinfo_t ti; ret = child_ops.to_wait (ptid, ourstatus); if (GET_PID(ret) >= 0 && ourstatus->kind == TARGET_WAITKIND_STOPPED) { lwp = get_current_lwp (GET_PID(ret)); ret = thread_from_lwp (BUILD_LWP(lwp, GET_PID(ret)), &th, &ti); if (!in_thread_list(ret)) { /* * We have to enable event reporting for initial thread * which was not mapped before. */ attach_thread(ret, &th, &ti, 1); } if (ourstatus->value.sig == TARGET_SIGNAL_TRAP) check_event(ret); /* this is a hack, if an event won't cause gdb to stop, for example, SIGARLM, gdb resumes the process immediatly without setting inferior_ptid to the new thread returned here, this is a bug because inferior_ptid may already not exist there, and passing a none existing thread to fbsd_thread_resume causes error. */ if (!fbsd_thread_alive (inferior_ptid)) { delete_thread (inferior_ptid); inferior_ptid = ret; } } return (ret); }
/*----------------------------------------------------------------------------*/ status_t kill_thread(thread_id thread) { sys_thread_info_t *curr_th = NULL; sys_thread_info_t **prev_th = NULL; int status; if(acquire_sem(_thread_list_sem) == B_OK) { curr_th = _thread_list; prev_th = &_thread_list; while(curr_th) { if(curr_th->info.thread == thread) { /* thread found, remove it... */ *prev_th = curr_th->next; status = pthread_cancel((pthread_t)thread); DBG(OUT("Killed thread %d (%s)\n", thread, curr_th->info.name)); delete_thread(curr_th); release_sem(_thread_list_sem); if(status != 0) { switch(errno) { case EINVAL: case ESRCH: return B_BAD_THREAD_ID; } } return B_OK; } prev_th = &(curr_th->next); curr_th = curr_th->next; } release_sem(_thread_list_sem); } return B_BAD_THREAD_ID; }
static int test_update(void) { logbuffer_t logbuf = logbuffer_FREE; thread_t * thread = 0; pipe_t pipe = pipe_FREE; uint8_t buffer[1024]; uint8_t readbuffer[1024+1]; // prepare TEST(0 == init_pipe(&pipe)); logbuf = (logbuffer_t) logbuffer_INIT(sizeof(buffer), buffer, pipe.write); // TEST truncate_logbuffer for (unsigned i = 0; i < 32; ++i) { logbuf.logsize = 32; logbuf.addr[i] = 'a'; truncate_logbuffer(&logbuf, i); TEST(logbuf.addr == buffer); TEST(logbuf.size == sizeof(buffer)); TEST(logbuf.io == pipe.write); TEST(logbuf.addr[i] == 0); TEST(logbuf.logsize == i); } // TEST truncate_logbuffer: parameter with bigger or equal size are ignored for (unsigned i = 0; i < 32; ++i) { logbuf.logsize = i; logbuf.addr[i] = 'a'; logbuf.addr[i+1] = 'a'; truncate_logbuffer(&logbuf, i+1); truncate_logbuffer(&logbuf, i); TEST(logbuf.addr == buffer); TEST(logbuf.size == sizeof(buffer)); TEST(logbuf.io == pipe.write); TEST(logbuf.addr[i] == 'a'); TEST(logbuf.addr[i+1] == 'a'); TEST(logbuf.logsize == i); } // TEST write_logbuffer memset(readbuffer, 0, sizeof(readbuffer)); for (unsigned i = 0; i < sizeof(buffer); ++i) { buffer[i] = (uint8_t)i; } logbuf.logsize = logbuf.size; // test TEST( 0 == write_logbuffer(&logbuf)); // check logbuf TEST( logbuf.addr == buffer); TEST( logbuf.size == sizeof(buffer)); TEST( logbuf.logsize == sizeof(buffer)); TEST( logbuf.io == pipe.write); // check content of pipe static_assert(sizeof(readbuffer) > sizeof(buffer), "check that only sizeof(buffer) are written"); TEST(sizeof(buffer) == read(pipe.read, readbuffer, sizeof(readbuffer))); for (unsigned i = 0; i < sizeof(buffer); ++i) { TEST(buffer[i] == readbuffer[i]); } // TEST printheader_logbuffer logbuf.logsize = 0; log_header_t header = log_header_INIT("test_update", "file", 123456); printheader_logbuffer(&logbuf, &header); TEST(0 == compare_header(logbuf.logsize, logbuf.addr, "test_update", "file", 123456)); for (size_t len = logbuf.logsize, i = 1; i < 10; ++i) { printheader_logbuffer(&logbuf, &header); TEST((i+1)*len == logbuf.logsize); TEST(0 == compare_header(len, logbuf.addr + i*len, "test_update", "file", 123456)); } // TEST printheader_logbuffer: other thread TEST(0 == newgeneric_thread(&thread, &thread_printheader, &logbuf)); TEST(0 == join_thread(thread)); TEST(0 == returncode_thread(thread)); TEST(0 == delete_thread(&thread)); // TEST printheader_logbuffer: adds " ..." at end in case of truncated message logbuf.logsize = logbuf.size - 10; logbuf.addr[logbuf.logsize] = 0; printheader_logbuffer(&logbuf, &header); TEST(logbuf.logsize == logbuf.size - 1) TEST(0 == memcmp(logbuf.addr + logbuf.size - 10, "[", 1)); TEST(0 == memcmp(logbuf.addr + logbuf.size - 5, " ...", 5)); // TEST vprintf_logbuffer: append on already stored content for (unsigned i = 0; i < sizeof(buffer)-100; ++i) { memset(buffer, 0, sizeof(buffer)); memset(readbuffer, 0, sizeof(readbuffer)); logbuf.logsize = i; printf_logbuffer(&logbuf, "%d : %s : %c;;", i, "OK!", '0'); snprintf((char*)readbuffer + i, 100, "%d : %s : %c;;", i, "OK!", '0'); TEST(0 == memcmp(buffer, readbuffer, sizeof(buffer))); } // TEST vprintf_logbuffer: different formats logbuf.logsize = 0; printf_logbuffer(&logbuf, "%%%s%%", "str" ); printf_logbuffer(&logbuf, "%"PRIi8";", (int8_t)-1); printf_logbuffer(&logbuf, "%"PRIu8";", (uint8_t)1); printf_logbuffer(&logbuf, "%"PRIi16";", (int16_t)-256); printf_logbuffer(&logbuf, "%"PRIu16";", (uint16_t)256); printf_logbuffer(&logbuf, "%"PRIi32";", (int32_t)-65536); printf_logbuffer(&logbuf, "%"PRIu32";", (uint32_t)65536); printf_logbuffer(&logbuf, "%zd;", (ssize_t)-65536); printf_logbuffer(&logbuf, "%zu;", (size_t)65536); printf_logbuffer(&logbuf, "%g;", 2e100); printf_logbuffer(&logbuf, "%.0f;", (double)1234567); const char * result = "%str%-1;1;-256;256;-65536;65536;-65536;65536;2e+100;1234567;"; TEST(strlen(result) == logbuf.logsize); TEST(0 == memcmp(logbuf.addr, result, logbuf.logsize)); // TEST vprintf_logwriter: adds " ..." at end in case of truncated message char strtoobig[100]; memset(strtoobig, '1', sizeof(strtoobig)); logbuf.logsize = logbuf.size - sizeof(strtoobig); logbuf.addr[logbuf.logsize] = 0; printf_logbuffer(&logbuf, "%.100s", strtoobig); TEST(logbuf.logsize == logbuf.size - 1) TEST(0 == memcmp(logbuf.addr + logbuf.size - sizeof(strtoobig), strtoobig, sizeof(strtoobig)-5)); TEST(0 == memcmp(logbuf.addr + logbuf.size - 5, " ...", 5)); // TEST vprintf_logbuffer: format == 0 logbuf.logsize = 0; printf_logbuffer(&logbuf, 0); // nothing printed TEST(0 == logbuf.logsize); // TEST vprintf_logbuffer: sizefree_logbuffer() == 0 logbuf.logsize = logbuf.size; memset(logbuf.addr, 255, logbuf.size); printf_logbuffer(&logbuf, "%d", 12345); // check logbuf not changed TEST(buffer == logbuf.addr); TEST(sizeof(buffer) == logbuf.size); TEST(sizeof(buffer) == logbuf.logsize); TEST(pipe.write == logbuf.io); // check content of logbuf not changed except for " ..." for (size_t i = 0; i < logbuf.logsize - 5; ++i) { TEST(255 == logbuf.addr[i]); } TEST(0 == memcmp(logbuf.addr + logbuf.logsize - 5, " ...", 4)); TEST(255 == logbuf.addr[logbuf.logsize-1]); // TEST vprintf_logbuffer: logbuffer_t.size <= 5 for (size_t s = 5; s <= 5; --s) { TEST(sizeof(buffer) == logbuf.size); logbuf.size = s; logbuf.logsize = 0; memset(logbuf.addr, 255, s); printf_logbuffer(&logbuf, "%d", 12345); // check logbuf TEST(buffer == logbuf.addr); TEST(s == logbuf.size); TEST((s?s-1:0) == logbuf.logsize); TEST(pipe.write == logbuf.io); // check content of logbuf if (s == 5) { // " ..." TEST(0 == memcmp(logbuf.addr, " ...", 5)); } else { // truncated 12345 for (size_t i = 0; i < logbuf.logsize; ++i) { TEST(i+'1' == logbuf.addr[i]); } TEST(0 == (logbuf.size ? logbuf.addr[logbuf.size-1] : 0)); } // reset logbuf.size = sizeof(buffer); } // unprepare TEST(-1 == read(pipe.read, readbuffer, sizeof(readbuffer))); TEST(0 == free_pipe(&pipe)); return 0; ONERR: delete_thread(&thread); free_pipe(&pipe); return EINVAL; }
/* * Check the min_spare_threads and max_spare_threads. * * If there are too many or too few threads waiting, then we * either create some more, or delete some. */ static void thread_pool_manage(time_t now) { int spare; int i, total; THREAD_HANDLE *handle, *next; int active_threads; /* * We don't need a mutex lock here, as we're reading * active_threads, and not modifying it. We want a close * approximation of the number of active threads, and this * is good enough. */ active_threads = thread_pool.active_threads; spare = thread_pool.total_threads - active_threads; if (debug_flag) { static int old_total = -1; static int old_active = -1; if ((old_total != thread_pool.total_threads) || (old_active != active_threads)) { DEBUG2("Threads: total/active/spare threads = %d/%d/%d", thread_pool.total_threads, active_threads, spare); old_total = thread_pool.total_threads; old_active = active_threads; } } /* * If there are too few spare threads. Go create some more. */ if ((thread_pool.total_threads < thread_pool.max_threads) && (spare < thread_pool.min_spare_threads)) { total = thread_pool.min_spare_threads - spare; if ((total + thread_pool.total_threads) > thread_pool.max_threads) { total = thread_pool.max_threads - thread_pool.total_threads; } DEBUG2("Threads: Spawning %d spares", total); /* * Create a number of spare threads. */ for (i = 0; i < total; i++) { handle = spawn_thread(now, 1); if (handle == NULL) { return; } } return; /* there aren't too many spare threads */ } /* * Only delete spare threads if we haven't already done * so this second. */ if (now == last_cleaned) { return; } last_cleaned = now; /* * Loop over the thread pool, deleting exited threads. */ for (handle = thread_pool.head; handle; handle = next) { next = handle->next; /* * Maybe we've asked the thread to exit, and it * has agreed. */ if (handle->status == THREAD_EXITED) { pthread_join(handle->pthread_id, NULL); delete_thread(handle); } } /* * Only delete the spare threads if sufficient time has * passed since we last created one. This helps to minimize * the amount of create/delete cycles. */ if ((now - thread_pool.time_last_spawned) < thread_pool.cleanup_delay) { return; } /* * If there are too many spare threads, delete one. * * Note that we only delete ONE at a time, instead of * wiping out many. This allows the excess servers to * be slowly reaped, just in case the load spike comes again. */ if (spare > thread_pool.max_spare_threads) { spare -= thread_pool.max_spare_threads; DEBUG2("Threads: deleting 1 spare out of %d spares", spare); /* * Walk through the thread pool, deleting the * first idle thread we come across. */ for (handle = thread_pool.head; (handle != NULL) && (spare > 0) ; handle = next) { next = handle->next; /* * If the thread is not handling a * request, but still live, then tell it * to exit. * * It will eventually wake up, and realize * it's been told to commit suicide. */ if ((handle->request == NULL) && (handle->status == THREAD_RUNNING)) { handle->status = THREAD_CANCELLED; /* * Post an extra semaphore, as a * signal to wake up, and exit. */ sem_post(&thread_pool.semaphore); spare--; break; } } } /* * If the thread has handled too many requests, then make it * exit. */ if (thread_pool.max_requests_per_thread > 0) { for (handle = thread_pool.head; handle; handle = next) { next = handle->next; /* * Not handling a request, but otherwise * live, we can kill it. */ if ((handle->request == NULL) && (handle->status == THREAD_RUNNING) && (handle->request_count > thread_pool.max_requests_per_thread)) { handle->status = THREAD_CANCELLED; sem_post(&thread_pool.semaphore); } } } /* * Otherwise everything's kosher. There are not too few, * or too many spare threads. Exit happily. */ return; }
static int test_logininfo(void) { syslogin_info_t* info = 0; thread_t* thr = 0; uid_t uid; gid_t gid; int fd[2] = { -1, -1 }; uint8_t buffer[16]; // prepare TEST(0 == pipe2(fd, O_CLOEXEC|O_NONBLOCK)); // == lifetime == for (unsigned entrypos = 0; true; ++entrypos) { setpwent(); for (unsigned i = 0; i < entrypos; ++i) { TEST(0 != getpwent()); } struct passwd* pwd = getpwent(); if (pwd == 0) { TEST(entrypos > 2); // tested at least 2 entries break; } uid = pwd->pw_uid; gid = pwd->pw_gid; // TEST new_syslogininfo: read entries TEST(0 == new_syslogininfo(&info, uid)); TEST(0 != info); TEST(0 < info->size); TEST(uid == info->uid); TEST(1 <= info->nrgroups); TEST(info->nrgroups > info->gmain); TEST(gid == info->gid[info->gmain]); // check memory addr TEST(info->gname == (const char**)(&info[1])); TEST(info->gid == (sys_groupid_t*)((uint8_t*)info->gname + info->nrgroups * sizeof(char*))); TEST(info->uname == (const char*)((uint8_t*)info->gid + info->nrgroups * sizeof(sys_groupid_t))); TEST(info->gname[0] == info->uname + strlen(info->uname) + 1); TEST((uint8_t*)info + info->size == (const uint8_t*)info->gname[info->nrgroups-1] + strlen(info->gname[info->nrgroups-1]) + 1); for (size_t i = 1; i < info->nrgroups; ++i) { TEST(info->gname[i-1] + strlen(info->gname[i-1]) + 1 == info->gname[i]); } // DEBUG printf("user %s(%d) groups ", info->uname, info->uid); // DEBUG for (size_t i = 0; i < info->nrgroups; ++i) { // DEBUG if (i == info->gmain) printf("*"); // DEBUG printf("%s(%d),", info->gname[i], info->gid[i]); // DEBUG } // DEBUG printf("\n"); // TEST delete_syslogininfo TEST(0 != info); TEST(0 == delete_syslogininfo(&info)); TEST(0 == info); TEST(0 == delete_syslogininfo(&info)); TEST(0 == info); } // TEST new_syslogininfo: lock TEST(0 == new_thread(&thr, &thread_initinfo, (void*)(intptr_t)fd[1])); TEST(0 == lock_mutex(&s_syslogininfo_lock)); struct pollfd pfd = { .fd = fd[0], .events = POLLIN }; TEST(1 == poll(&pfd, 1, 10000)); TEST(1 == read(fd[0], buffer, sizeof(buffer))); TEST(EBUSY == tryjoin_thread(thr)); TEST(-1 == read(fd[0], buffer, sizeof(buffer))); TEST(EAGAIN == errno); TEST(0 == unlock_mutex(&s_syslogininfo_lock)); TEST(0 == join_thread(thr)); TEST(0 == returncode_thread(thr)); TEST(0 == delete_thread(&thr)); // TEST new_syslogininfo: ENOENT info = (void*)1; TEST(ENOENT == new_syslogininfo(&info, (uid_t)-2)); TEST((void*)1 == info); info = 0; // == query == // TEST username_syslogininfo syslogin_info_t info2; info2.uname = 0; TEST(0 == username_syslogininfo(&info2)); for (uintptr_t i = 1; i; i <<= 1) { info2.uname = (const char*)i; TEST((const char*)i == username_syslogininfo(&info2)); } // unprepare TEST(0 == close(fd[0])); TEST(0 == close(fd[1])); return 0; ONERR: if (info != (void*)1) { delete_syslogininfo(&info); } close(fd[0]); close(fd[1]); return EINVAL; }