long gwthread_create_real(gwthread_func_t *func, const char *name, void *arg) { int sigtrick = 0; sigset_t old_signal_set; long thread_id; /* * We want to make sure that only the main thread handles signals, * so that each signal is handled exactly once. To do this, we * make sure that each new thread has all the signals that we * handle blocked. To avoid race conditions, we block them in * the spawning thread first, then create the new thread (which * inherits the settings), and then restore the old settings in * the spawning thread. This means that there is a brief period * when no signals will be processed, but during that time they * should be queued by the operating system. */ if (gwthread_self() == MAIN_THREAD_ID) sigtrick = block_user_signals(&old_signal_set) == 0; thread_id = spawn_thread(func, name, arg); /* * Restore the old signal mask. The new thread will have * inherited the resticted one, but the main thread needs * the old one back. */ if (sigtrick) restore_user_signals(&old_signal_set); return thread_id; }
void *gwlist_timed_consume(List *list, long sec) { void *item; struct timespec abstime; int rc; abstime.tv_sec = time(NULL) + sec; abstime.tv_nsec = 0; lock(list); ++list->num_consumers; while (list->len == 0 && list->num_producers > 0) { list->single_operation_lock->owner = -1; rc = pthread_cond_timedwait(&list->nonempty, &list->single_operation_lock->mutex, &abstime); list->single_operation_lock->owner = gwthread_self(); if (rc == ETIMEDOUT) break; } if (list->len > 0) { item = GET(list, 0); delete_items_from_list(list, 0, 1); } else { item = NULL; } --list->num_consumers; unlock(list); return item; }
/* Lock a Connection's write direction, if the Connection is unclaimed */ static void inline lock_out(Connection *conn) { gw_assert(conn != NULL); if (conn->claimed) gw_assert(gwthread_self() == conn->claiming_thread); else mutex_lock(conn->outlock); }
void gwthread_wakeup_all(void) { long i; long our_thread = gwthread_self(); for (i = 0; i < THREADTABLE_SIZE; ++i) { if (THREAD(our_thread) != THREAD(i)) gwthread_wakeup(i); } }
void conn_claim(Connection *conn) { gw_assert(conn != NULL); if (conn->claimed) panic(0, "Connection is being claimed twice!"); conn->claimed = 1; #ifndef NO_GWASSERT conn->claiming_thread = gwthread_self(); #endif }
static void *new_thread(void *arg) { int ret; struct new_thread_args *p = arg; /* Make sure we don't start until our parent has entered * our thread info in the thread table. */ lock(); /* check for initialization errors */ if (p->failed) { /* Must free p before signaling our exit, otherwise there is * a race with gw_check_leaks at shutdown. */ gw_free(p); delete_threadinfo(); unlock(); return NULL; } unlock(); /* This has to be done here, because pthread_setspecific cannot * be called by our parent on our behalf. That's why the ti * pointer is passed in the new_thread_args structure. */ /* Synchronization is not a problem, because the only thread * that relies on this call having been made is this one -- * no other thread can access our TSD anyway. */ ret = pthread_setspecific(tsd_key, p->ti); if (ret != 0) { panic(ret, "gwthread-pthread: pthread_setspecific failed"); } p->ti->pid = getpid(); debug("gwlib.gwthread", 0, "Thread %ld (%s) maps to pid %ld.", p->ti->number, p->ti->name, (long) p->ti->pid); (p->func)(p->arg); lock(); debug("gwlib.gwthread", 0, "Thread %ld (%s) terminates.", p->ti->number, p->ti->name); alert_joiners(); #ifdef HAVE_LIBSSL /* Clear the OpenSSL thread-specific error queue to avoid * memory leaks. */ ERR_remove_state(gwthread_self()); #endif /* HAVE_LIBSSL */ /* Must free p before signaling our exit, otherwise there is * a race with gw_check_leaks at shutdown. */ gw_free(p); delete_threadinfo(); unlock(); return NULL; }
static void producer(void *arg) { long i, index; long id; struct producer_info *info; info = arg; id = gwthread_self(); index = info->start_index; for (i = 0; i < NUM_ITEMS_PER_PRODUCER; ++i, ++index) gwlist_produce(info->list, new_item(id, i, index)); gwlist_remove_producer(info->list); }
static void client_thread(void *arg) { List *reqh; unsigned long i; long succeeded, failed; HTTPCaller *caller; char buf[1024]; long in_queue; Counter *counter = NULL; caller = arg; succeeded = 0; failed = 0; reqh = gwlist_create(); sprintf(buf, "%ld", (long) gwthread_self()); http_header_add(reqh, "X-Thread", buf); if (auth_username != NULL && auth_password != NULL) http_add_basic_auth(reqh, auth_username, auth_password); in_queue = 0; counter = counter_create(); for (;;) { i = counter_increase(counter); if (i >= max_requests) goto receive_rest; start_request(caller, reqh, i); if (interval > 0) gwthread_sleep(interval); ++in_queue; if (receive_reply(caller) == -1) ++failed; else ++succeeded; --in_queue; } receive_rest: while (in_queue > 0) { if (receive_reply(caller) == -1) ++failed; else ++succeeded; --in_queue; } counter_destroy(counter); http_destroy_headers(reqh); http_caller_destroy(caller); info(0, "This thread: %ld succeeded, %ld failed.", succeeded, failed); }
static void push_thread(void *arg) { HTTPCaller *caller; long succeeded, failed, in_queue; unsigned long i; caller = arg; succeeded = 0; failed = 0; in_queue = 0; i = 0; for (;;) { while (in_queue < MAX_IN_QUEUE) { i = counter_increase(counter); if (i >= max_pushes) goto receive_rest; start_push(caller, i); if (wait_seconds > 0) gwthread_sleep(wait_seconds); ++in_queue; } while (in_queue >= MAX_IN_QUEUE) { if (receive_push_reply(caller) == -1) ++failed; else ++succeeded; --in_queue; } } receive_rest: while (in_queue > 0) { if (receive_push_reply(caller) == -1) ++failed; else ++succeeded; --in_queue; } http_caller_destroy(caller); info(0, "TEST_PPG: In thread %ld %ld succeeded, %ld failed", (long) gwthread_self(), succeeded, failed); }
int list_wait_until_nonempty(List *list) { int ret; lock(list); while (list->len == 0 && list->num_producers > 0) { list->single_operation_lock->owner = -1; pthread_cond_wait(&list->nonempty, &list->single_operation_lock->mutex); list->single_operation_lock->owner = gwthread_self(); } if (list->len > 0) ret = 1; else ret = -1; unlock(list); return ret; }
static void new_thread_cleanup(void *arg) { struct new_thread_args *p = arg; lock(); debug("gwlib.gwthread", 0, "Thread %ld (%s) terminates.", p->ti->number, p->ti->name); alert_joiners(); #ifdef HAVE_LIBSSL /* Clear the OpenSSL thread-specific error queue to avoid * memory leaks. */ ERR_remove_state(gwthread_self()); #endif /* HAVE_LIBSSL */ /* Must free p before signaling our exit, otherwise there is * a race with gw_check_leaks at shutdown. */ gw_free(p); delete_threadinfo(); unlock(); }
void *list_consume(List *list) { void *item; lock(list); while (list->len == 0 && list->num_producers > 0) { list->single_operation_lock->owner = -1; pthread_cond_wait(&list->nonempty, &list->single_operation_lock->mutex); list->single_operation_lock->owner = gwthread_self(); } if (list->len > 0) { item = GET(list, 0); delete_items_from_list(list, 0, 1); } else { item = NULL; } unlock(list); return item; }
int gw_rwlock_unlock(RWLock *lock) { int ret = 0; gw_assert(lock != NULL); #ifdef HAVE_PTHREAD_RWLOCK ret = pthread_rwlock_unlock(&lock->rwlock); if (ret != 0) panic(ret, "Error while gw_rwlock_unlock."); #else RWDEBUG("", 0, "------------ gw_rwlock_unlock(%p) ----------", lock); if (lock->writer == gwthread_self()) { lock->writer = -1; gwlist_unlock(lock->rwlock); } else gwlist_remove_producer(lock->rwlock); #endif return ret; }
int gw_rwlock_wrlock(RWLock *lock) { int ret = 0; gw_assert(lock != NULL); #ifdef HAVE_PTHREAD_RWLOCK ret = pthread_rwlock_wrlock(&lock->rwlock); if (ret != 0) panic(ret, "Error while pthread_rwlock_wrlock."); #else RWDEBUG("", 0, "------------ gw_rwlock_wrlock(%p) ----------", lock); gwlist_lock(lock->rwlock); RWDEBUG("", 0, "------------ gw_rwlock_wrlock(%p) producers=%d", lock, gwlist_producer_count(lock->rwlock)); /* wait for reader */ gwlist_consume(lock->rwlock); lock->writer = gwthread_self(); #endif return ret; }
void *gw_prioqueue_consume(gw_prioqueue_t *queue) { void *ret; gw_assert(queue != NULL); queue_lock(queue); while (queue->len == 1 && queue->producers > 0) { queue->mutex->owner = -1; pthread_cond_wait(&queue->nonempty, &queue->mutex->mutex); queue->mutex->owner = gwthread_self(); } if (queue->len > 1) { ret = queue->tab[1]->item; gw_free(queue->tab[1]); queue->tab[1] = queue->tab[--queue->len]; downheap(queue, 1); } else { ret = NULL; } queue_unlock(queue); return ret; }
static void format(char *buf, int level, const char *place, int e, const char *fmt, int with_timestamp_and_pid) { static char *tab[] = { "DEBUG: ", "INFO: ", "WARNING: ", "ERROR: ", "PANIC: ", "LOG: " }; static int tab_size = sizeof(tab) / sizeof(tab[0]); time_t t; struct tm tm; char *p, prefix[1024]; long tid, pid; p = prefix; if (with_timestamp_and_pid) { time(&t); #if LOG_TIMESTAMP_LOCALTIME tm = gw_localtime(t); #else tm = gw_gmtime(t); #endif sprintf(p, "%04d-%02d-%02d %02d:%02d:%02d ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); p = strchr(p, '\0'); /* print PID and thread ID */ gwthread_self_ids(&tid, &pid); sprintf(p, "[%ld] [%ld] ", pid, tid); } else { /* thread ID only */ tid = gwthread_self(); sprintf(p, "[%ld] ", tid); } p = strchr(p, '\0'); if (level < 0 || level >= tab_size) sprintf(p, "UNKNOWN: "); else sprintf(p, "%s", tab[level]); p = strchr(p, '\0'); if (place != NULL && *place != '\0') sprintf(p, "%s: ", place); if (strlen(prefix) + strlen(fmt) > FORMAT_SIZE / 2) { sprintf(buf, "%s <OUTPUT message too long>\n", prefix); return; } if (e == 0) sprintf(buf, "%s%s\n", prefix, fmt); else sprintf(buf, "%s%s\n%sSystem error %d: %s\n", prefix, fmt, prefix, e, strerror(e)); }
/* Somewhat broken pthreads */ int gwthread_shouldhandlesignal(int signal){ return (gwthread_self() == MAIN_THREAD_ID); }