static SilcThreadPoolThread silc_thread_pool_new_thread(SilcThreadPool tp) { SilcThreadPoolThread t; t = silc_scalloc(tp->stack, 1, sizeof(*t)); if (!t) return NULL; if (!silc_mutex_alloc(&t->lock)) { silc_sfree(tp->stack, t); return NULL; } if (!silc_cond_alloc(&t->thread_signal)) { silc_mutex_free(t->lock); silc_sfree(tp->stack, t); return NULL; } t->tp = tp; silc_list_init(t->queue, struct SilcThreadPoolThreadStruct, next); silc_list_init(t->free_queue, struct SilcThreadPoolThreadStruct, next); /* Add to thread pool */ silc_list_add(tp->threads, t); silc_list_add(tp->free_threads, t); silc_thread_pool_ref(tp); SILC_LOG_DEBUG(("Start thread %p", t)); /* Start the thread */ silc_thread_create(silc_thread_pool_run_thread, t, FALSE); return t; }
void silc_client_free(SilcClient client) { if (client->schedule) silc_schedule_uninit(client->schedule); if (client->rng) silc_rng_free(client->rng); if (!client->internal->params->dont_register_crypto_library) { silc_cipher_unregister_all(); silc_pkcs_unregister_all(); silc_hash_unregister_all(); silc_hmac_unregister_all(); } if (client->internal->packet_engine) silc_packet_engine_stop(client->internal->packet_engine); if (client->internal->ftp_sessions) silc_dlist_uninit(client->internal->ftp_sessions); if (client->internal->lock) silc_mutex_free(client->internal->lock); silc_atomic_uninit32(&client->internal->conns); silc_free(client->username); silc_free(client->hostname); silc_free(client->realname); silc_free(client->internal->params); silc_free(client->internal->silc_client_version); silc_free(client->internal); silc_free(client); }
SilcThreadPool silc_thread_pool_alloc(SilcStack stack, SilcUInt32 min_threads, SilcUInt32 max_threads, SilcBool start_min_threads) { SilcThreadPool tp; int i; if (max_threads < min_threads) { silc_set_errno_reason(SILC_ERR_INVALID_ARGUMENT, "Max threads is smaller than min threads (%d < %d)", max_threads, min_threads); return NULL; } if (!max_threads) { silc_set_errno_reason(SILC_ERR_INVALID_ARGUMENT, "Max threads is 0"); return NULL; } if (stack) stack = silc_stack_alloc(0, stack); tp = silc_scalloc(stack, 1, sizeof(*tp)); if (!tp) { silc_stack_free(stack); return NULL; } SILC_LOG_DEBUG(("Starting thread pool %p, min threads %d, max threads %d", tp, min_threads, max_threads)); tp->stack = stack; tp->min_threads = min_threads; tp->max_threads = max_threads; tp->refcnt++; if (!silc_mutex_alloc(&tp->lock)) { silc_sfree(stack, tp); silc_stack_free(stack); return NULL; } if (!silc_cond_alloc(&tp->pool_signal)) { silc_mutex_free(tp->lock); silc_sfree(stack, tp); silc_stack_free(stack); return NULL; } silc_list_init(tp->threads, struct SilcThreadPoolThreadStruct, next); silc_list_init(tp->free_threads, struct SilcThreadPoolThreadStruct, next2); for (i = 0; i < tp->min_threads && start_min_threads; i++) silc_thread_pool_new_thread(tp); silc_list_start(tp->threads); return tp; }
void silc_rwlock_free(SilcRwLock rwlock) { #ifdef SILC_THREADS if (rwlock) { silc_mutex_free(rwlock->mutex); silc_cond_free(rwlock->cond); silc_free(rwlock); } #endif /* SILC_THREADS */ }
static void silc_thread_pool_unref(SilcThreadPool tp) { tp->refcnt--; SILC_LOG_DEBUG(("Thread pool %p refcnt %d -> %d", tp, tp->refcnt + 1, tp->refcnt)); if (!tp->refcnt) { SilcStack stack = tp->stack; silc_mutex_unlock(tp->lock); silc_mutex_free(tp->lock); silc_cond_free(tp->pool_signal); silc_sfree(stack, tp); silc_stack_free(stack); return; } silc_mutex_unlock(tp->lock); }
void silc_thread_tls_uninit(void) { SilcTls tls = silc_thread_get_tls(); if (!tls || tls->shared_data) return; if (tls->tls_variables) silc_hash_table_free(tls->tls_variables); if (tls->variables) silc_hash_table_free(tls->variables); if (tls->lock) silc_mutex_free(tls->lock); tls->variables = NULL; tls->lock = NULL; }
SilcBool silc_rwlock_alloc(SilcRwLock *rwlock) { #ifdef SILC_THREADS *rwlock = (SilcRwLock)silc_calloc(1, sizeof(**rwlock)); if (!(*rwlock)) return FALSE; if (!silc_mutex_alloc(&(*rwlock)->mutex)) { silc_free(*rwlock); return FALSE; } if (!silc_cond_alloc(&(*rwlock)->cond)) { silc_mutex_free((*rwlock)->mutex); silc_free(*rwlock); return FALSE; } return TRUE; #else return FALSE; #endif /* SILC_THREADS */ }
void silc_client_del_connection(SilcClient client, SilcClientConnection conn) { SilcList list; SilcIDCacheEntry entry; SilcFSMThread thread; SILC_LOG_DEBUG(("Freeing connection %p", conn)); silc_schedule_task_del_by_context(conn->internal->schedule, conn); /* Free all cache entries */ if (conn->internal->server_cache) { if (silc_idcache_get_all(conn->internal->server_cache, &list)) { silc_list_start(list); while ((entry = silc_list_get(list))) silc_client_del_server(client, conn, entry->context); } } if (conn->internal->channel_cache) { if (silc_idcache_get_all(conn->internal->channel_cache, &list)) { silc_list_start(list); while ((entry = silc_list_get(list))) { silc_client_empty_channel(client, conn, entry->context); silc_client_del_channel(client, conn, entry->context); } } } if (conn->internal->client_cache) { if (silc_idcache_get_all(conn->internal->client_cache, &list)) { silc_list_start(list); while ((entry = silc_list_get(list))) silc_client_del_client(client, conn, entry->context); } } /* Free ID caches */ if (conn->internal->client_cache) silc_idcache_free(conn->internal->client_cache); if (conn->internal->channel_cache) silc_idcache_free(conn->internal->channel_cache); if (conn->internal->server_cache) silc_idcache_free(conn->internal->server_cache); /* Free thread pool */ silc_list_start(conn->internal->thread_pool); while ((thread = silc_list_get(conn->internal->thread_pool))) silc_fsm_free(thread); silc_free(conn->remote_host); silc_buffer_free(conn->internal->local_idp); silc_buffer_free(conn->internal->remote_idp); silc_mutex_free(conn->internal->lock); if (conn->internal->hash) silc_hash_free(conn->internal->hash); if (conn->internal->sha1hash) silc_hash_free(conn->internal->sha1hash); silc_atomic_uninit16(&conn->internal->cmd_ident); silc_free(conn->internal->away_message); if (conn->internal->rekey) silc_ske_free_rekey_material(conn->internal->rekey); if (conn->internal->cop) silc_async_free(conn->internal->cop); silc_free(conn->internal); memset(conn, 'F', sizeof(*conn)); silc_free(conn); }
static void *silc_thread_pool_run_thread(void *context) { SilcThreadPoolThread t = context, o, q; SilcThreadPool tp = t->tp; SilcMutex lock = t->lock; SilcCond thread_signal = t->thread_signal; silc_mutex_lock(lock); while (1) { /* Wait here for code to execute */ while (!t->run && !t->stop) silc_cond_wait(thread_signal, lock); if (t->stop) goto stop; /* Execute code */ silc_mutex_unlock(lock); execute: SILC_LOG_DEBUG(("Execute call %p, context %p, thread %p", t->run, t->run_context, t)); t->run(t->schedule, t->run_context); /* If scheduler is NULL, call completion directly from here. Otherwise it is called through the scheduler in the thread where the scheduler is running. */ if (t->completion) { if (t->schedule) { SILC_LOG_DEBUG(("Run completion through scheduler %p", t->schedule)); if (!silc_schedule_task_add_timeout(t->schedule, t->completion, t->completion_context, 0, 0)) { SILC_LOG_DEBUG(("Run completion directly")); t->completion(NULL, NULL, 0, 0, t->completion_context); } silc_schedule_wakeup(t->schedule); } else { SILC_LOG_DEBUG(("Run completion directly")); t->completion(NULL, NULL, 0, 0, t->completion_context); } } silc_mutex_lock(lock); if (t->stop) goto stop; /* Check if there are calls in queue. Takes the most recently added call since new ones are added at the start of the list. */ if (silc_list_count(t->queue) > 0) { execute_queue: silc_list_start(t->queue); q = silc_list_get(t->queue); SILC_LOG_DEBUG(("Execute call from queue")); /* Execute this call now */ t->run = q->run; t->run_context = q->run_context; t->completion = q->completion; t->completion_context = q->completion_context; t->schedule = q->schedule; silc_list_del(t->queue, q); silc_list_add(t->free_queue, q); silc_mutex_unlock(lock); goto execute; } silc_mutex_unlock(lock); silc_mutex_lock(tp->lock); /* Nothing to do. Attempt to steal call from some other thread. */ o = silc_list_get(tp->threads); if (!o) { /* List wraps around */ silc_list_start(tp->threads); o = silc_list_get(tp->threads); } /* Check that the other thread is valid and has something to execute. */ silc_mutex_lock(o->lock); if (o == t || o->stop || silc_list_count(o->queue) == 0) { silc_mutex_unlock(o->lock); o = NULL; } if (o) { silc_mutex_unlock(tp->lock); silc_list_start(o->queue); q = silc_list_get(o->queue); SILC_LOG_DEBUG(("Execute call from queue from thread %p", o)); /* Execute this call now */ t->run = q->run; t->run_context = q->run_context; t->completion = q->completion; t->completion_context = q->completion_context; t->schedule = q->schedule; silc_list_del(o->queue, q); silc_list_add(o->free_queue, q); silc_mutex_unlock(o->lock); goto execute; } silc_mutex_lock(lock); if (t->stop) { silc_mutex_unlock(tp->lock); goto stop; } /* Now that we have the lock back, check the queue again. */ if (silc_list_count(t->queue) > 0) { silc_mutex_unlock(tp->lock); goto execute_queue; } /* The thread is now free for use again. */ t->run = NULL; t->completion = NULL; t->schedule = NULL; silc_list_add(tp->free_threads, t); silc_mutex_unlock(tp->lock); } stop: /* Stop the thread. Remove from threads list. */ SILC_LOG_DEBUG(("Stop thread %p", t)); /* We can unlock the thread now. After we get the thread pool lock no one can retrieve the thread anymore. */ silc_mutex_unlock(lock); silc_mutex_lock(tp->lock); silc_list_del(tp->threads, t); silc_list_start(tp->threads); /* Clear thread's call queue. */ silc_list_start(t->queue); silc_list_start(t->free_queue); while ((q = silc_list_get(t->queue))) silc_sfree(tp->stack, q); while ((q = silc_list_get(t->free_queue))) silc_sfree(tp->stack, q); /* Destroy the thread */ silc_mutex_free(lock); silc_cond_free(thread_signal); silc_sfree(tp->stack, t); /* If we are last thread, signal the waiting destructor. */ if (silc_list_count(tp->threads) == 0) silc_cond_signal(tp->pool_signal); /* Release pool reference. Releases lock also. */ silc_thread_pool_unref(tp); return NULL; }