/* * Initializes the thread subsystem, creating various worker threads. * * nthreads Number of worker event handler threads to spawn * main_base Event base for main thread */ void thread_init(int nthr, struct event_base *main_base, void (*dispatcher_callback)(evutil_socket_t, short, void *)) { int i; nthreads = nthr + 1; cqi_freelist = NULL; cb_mutex_initialize(&conn_lock); cb_mutex_initialize(&cqi_freelist_lock); cb_mutex_initialize(&init_lock); cb_cond_initialize(&init_cond); threads = calloc(nthreads, sizeof(LIBEVENT_THREAD)); if (! threads) { settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL, "Can't allocate thread descriptors: %s", strerror(errno)); exit(1); } thread_ids = calloc(nthreads, sizeof(cb_thread_t)); if (! thread_ids) { settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL, "Can't allocate thread descriptors: %s", strerror(errno)); exit(1); } setup_dispatcher(main_base, dispatcher_callback); for (i = 0; i < nthreads; i++) { if (!create_notification_pipe(&threads[i])) { exit(1); } threads[i].index = i; setup_thread(&threads[i]); } /* Create threads after we've done all the libevent setup. */ for (i = 0; i < nthreads; i++) { create_worker(worker_libevent, &threads[i], &thread_ids[i]); threads[i].thread_id = thread_ids[i]; } /* Wait for all the threads to set themselves up before returning. */ cb_mutex_enter(&init_lock); while (init_count < nthreads) { cb_cond_wait(&init_cond, &init_lock); } cb_mutex_exit(&init_lock); }
topkeys_t *topkeys_init(int max_keys) { static struct hash_ops my_hash_ops; topkeys_t *tk = calloc(sizeof(topkeys_t), 1); if (tk == NULL) { return NULL; } my_hash_ops.hashfunc = genhash_string_hash; my_hash_ops.hasheq = my_hash_eq; my_hash_ops.dupKey = NULL; my_hash_ops.dupValue = NULL; my_hash_ops.freeKey = NULL; my_hash_ops.freeValue = NULL; cb_mutex_initialize(&tk->mutex); tk->max_keys = max_keys; tk->list.next = &tk->list; tk->list.prev = &tk->list; tk->hash = genhash_init(max_keys, my_hash_ops); if (tk->hash == NULL) { return NULL; } return tk; }
/* * Set up a thread's information. */ static void setup_thread(LIBEVENT_THREAD *me) { me->type = GENERAL; me->base = event_base_new(); if (! me->base) { settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL, "Can't allocate event base\n"); exit(1); } /* Listen for notifications from other threads */ event_set(&me->notify_event, me->notify[0], EV_READ | EV_PERSIST, thread_libevent_process, me); event_base_set(me->base, &me->notify_event); if (event_add(&me->notify_event, 0) == -1) { settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL, "Can't monitor libevent notify pipe\n"); exit(1); } me->new_conn_queue = malloc(sizeof(struct conn_queue)); if (me->new_conn_queue == NULL) { settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL, "Failed to allocate memory for connection queue"); exit(EXIT_FAILURE); } cq_init(me->new_conn_queue); cb_mutex_initialize(&me->mutex); // Initialize threads' sub-document parser / handler me->subdoc_op = subdoc_op_alloc(); }
cache_t* cache_create(const char *name, size_t bufsize, size_t align, cache_constructor_t* constructor, cache_destructor_t* destructor) { cache_t* ret = calloc(1, sizeof(cache_t)); char* nm = strdup(name); void** ptr = calloc(initial_pool_size, bufsize); if (ret == NULL || nm == NULL || ptr == NULL) { free(ret); free(nm); free(ptr); return NULL; } cb_mutex_initialize(&ret->mutex); ret->name = nm; ret->ptr = ptr; ret->freetotal = initial_pool_size; ret->constructor = constructor; ret->destructor = destructor; #ifndef NDEBUG ret->bufsize = bufsize + 2 * sizeof(redzone_pattern); #else ret->bufsize = bufsize; #endif (void)align; return ret; }
/** The "work_collect" abstraction helps to make scatter/gather easier * when using work queue's. The main caller uses work_collect_init() * to initialize the work_collect tracking data structure. The * work_collect structure is then scattered across worker threads * (such as by using work_send()). The main thread then calls * work_collect_wait() to wait for N responses. A worker thread * invokes work_collect_one() when it's finished with its assigned * work and has one response to contribute. When N responses have * been counted, work_collect_wait() returns control back to the * main caller. */ int work_collect_init(work_collect *c, int count, void *data) { cb_assert(c); memset(c, 0, sizeof(work_collect)); c->count = count; c->data = data; cb_mutex_initialize(&c->collect_lock); cb_cond_initialize(&c->collect_cond); return 0; }
/** A work queue is a mechanism to allow thread-to-thread * communication in a libevent-based, multithreaded system. * * One thread can send work to another thread. The receiving thread * should be libevent-based, with a processing loop handled by * libevent. * * Use work_queue_init() to initialize a work_queue structure, * where the work_queue structure memory is owned by the caller. * * Returns true on success. */ bool work_queue_init(work_queue *m, struct event_base *event_base) { cb_assert(m != NULL); memset(m, 0, sizeof(work_queue)); cb_mutex_initialize(&m->work_lock); m->work_head = NULL; m->work_tail = NULL; m->num_items = 0; m->tot_sends = 0; m->tot_recvs = 0; m->event_base = event_base; cb_assert(m->event_base != NULL); if (!create_notification_pipe(m)) { return false; } event_set(&m->event, m->recv_fd, EV_READ | EV_PERSIST, work_recv, m); event_base_set(m->event_base, &m->event); if (event_add(&m->event, 0) == 0) { #ifdef WORK_DEBUG moxi_log_write("work_queue_init %x %x %x %d %d %u %llu\n", (int) pthread_self(), (int) m, (int) m->event_base, m->send_fd, m->recv_fd, m->work_head != NULL, m->tot_sends); #endif return true; } #ifdef WORK_DEBUG moxi_log_write("work_queue_init error\n"); #endif return false; }
void mcache_init(mcache *m, bool multithreaded, mcache_funcs *funcs, bool key_alloc) { assert(m); assert(funcs); m->funcs = funcs; m->key_alloc = key_alloc; m->map = NULL; m->max = 0; m->lru_head = NULL; m->lru_tail = NULL; m->oldest_live = 0; if (multithreaded) { m->lock = malloc(sizeof(cb_mutex_t)); if (m->lock != NULL) { cb_mutex_initialize(m->lock); } } else { m->lock = NULL; } mcache_reset_stats(m); }
/* * Initializes a connection queue. */ static void cq_init(CQ *cq) { cb_mutex_initialize(&cq->lock); cb_cond_initialize(&cq->cond); cq->head = NULL; cq->tail = NULL; }