SilcServerCommand silc_server_command_alloc(SilcServerThread thread) { SilcServerCommand cmd; silc_mutex_lock(thread->server->lock); /* Get command context from freelist or allocate new one. */ cmd = silc_list_get(thread->server->command_pool); if (!cmd) { silc_mutex_unlock(thread->server->lock); cmd = silc_calloc(1, sizeof(*cmd)); if (!cmd) return NULL; SILC_LOG_DEBUG(("Allocating command context %p", cmd)); cmd->thread = thread; return cmd; } SILC_LOG_DEBUG(("Get command context %p", cmd)); /* Delete from freelist */ silc_list_del(thread->server->command_pool, cmd); cmd->thread = thread; silc_mutex_unlock(thread->server->lock); return cmd; }
SilcPrivateMessageKeys silc_client_list_private_message_keys(SilcClient client, SilcClientConnection conn, SilcUInt32 *key_count) { SilcPrivateMessageKeys keys; SilcUInt32 count = 0; SilcList list; SilcIDCacheEntry id_cache; SilcClientEntry entry; if (!client || !conn) return NULL; silc_mutex_lock(conn->internal->lock); if (!silc_idcache_get_all(conn->internal->client_cache, &list)) { silc_mutex_unlock(conn->internal->lock); return NULL; } keys = silc_calloc(silc_list_count(list), sizeof(*keys)); if (!keys) { silc_mutex_unlock(conn->internal->lock); return NULL; } silc_list_start(list); while ((id_cache = silc_list_get(list))) { entry = id_cache->context; if (entry->internal.send_key) { keys[count].client_entry = entry; keys[count].cipher = (char *)silc_cipher_get_name(entry->internal. send_key); keys[count].key = (entry->internal.generated == FALSE ? entry->internal.key : NULL); keys[count].key_len = (entry->internal.generated == FALSE ? entry->internal.key_len : 0); count++; } } silc_mutex_unlock(conn->internal->lock); if (key_count) *key_count = count; return keys; }
void silc_thread_pool_free(SilcThreadPool tp, SilcBool wait_unfinished) { SilcThreadPoolThread t; SILC_LOG_DEBUG(("Free thread pool %p", tp)); silc_mutex_lock(tp->lock); tp->destroy = TRUE; /* Stop threads */ silc_list_start(tp->threads); while ((t = silc_list_get(tp->threads))) { silc_mutex_lock(t->lock); t->stop = TRUE; silc_cond_signal(t->thread_signal); silc_mutex_unlock(t->lock); } if (wait_unfinished) { SILC_LOG_DEBUG(("Wait threads to finish")); while (silc_list_count(tp->threads)) silc_cond_wait(tp->pool_signal, tp->lock); } /* Release reference. Releases lock also. */ silc_thread_pool_unref(tp); }
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); }
SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex, int timeout) { #ifdef SILC_THREADS DWORD ret, t = INFINITE; if (timeout) t = timeout; while (TRUE) { cond->waiters++; silc_mutex_unlock(mutex); ret = WaitForSingleObject(cond->event, t); silc_mutex_lock(mutex); cond->waiters--; if (ret != WAIT_OBJECT_0) return FALSE; if (cond->signal) { cond->signal = FALSE; ResetEvent(cond->event); break; } } #endif /* SILC_THREADS*/ return TRUE; }
void silc_thread_pool_set_max_threads(SilcThreadPool tp, SilcUInt32 max_threads) { SILC_LOG_DEBUG(("Set thread pool %p max threads to %d", tp, max_threads)); silc_mutex_lock(tp->lock); tp->max_threads = max_threads; silc_mutex_unlock(tp->lock); }
void silc_rwlock_unlock(SilcRwLock rwlock) { #ifdef SILC_THREADS if (rwlock) { if (rwlock->locked) { /* Unlock writer */ rwlock->locked = FALSE; silc_mutex_unlock(rwlock->mutex); return; } /* Unlock reader */ silc_mutex_lock(rwlock->mutex); rwlock->readers--; silc_cond_broadcast(rwlock->cond); silc_mutex_unlock(rwlock->mutex); } #endif /* SILC_THREADS */ }
void silc_rwlock_rdlock(SilcRwLock rwlock) { #ifdef SILC_THREADS if (rwlock) { silc_mutex_lock(rwlock->mutex); rwlock->readers++; silc_mutex_unlock(rwlock->mutex); } #endif /* SILC_THREADS */ }
SilcUInt32 silc_thread_pool_num_free_threads(SilcThreadPool tp) { SilcUInt32 free_threads; silc_mutex_lock(tp->lock); free_threads = silc_list_count(tp->free_threads); silc_mutex_unlock(tp->lock); return free_threads; }
SilcUInt32 silc_thread_pool_get_max_threads(SilcThreadPool tp) { SilcUInt32 max_threads; silc_mutex_lock(tp->lock); max_threads = tp->max_threads; silc_mutex_unlock(tp->lock); return max_threads; }
SilcServerPending silc_server_command_pending_get(SilcServerThread thread, SilcUInt16 cmd_ident) { SilcServerPending pending = NULL; silc_mutex_lock(thread->server->lock); silc_hash_table_find(thread->server->pending_commands, SILC_32_TO_PTR(cmd_ident), NULL, (void **)&pending); silc_mutex_unlock(thread->server->lock); return pending; }
void silc_thread_pool_purge(SilcThreadPool tp) { SilcThreadPoolThread t; int i; silc_mutex_lock(tp->lock); if (silc_list_count(tp->free_threads) <= tp->min_threads) { SILC_LOG_DEBUG(("No threads to purge")); silc_mutex_unlock(tp->lock); return; } i = silc_list_count(tp->free_threads) - tp->min_threads; SILC_LOG_DEBUG(("Purge %d threads", i)); silc_list_start(tp->threads); while ((t = silc_list_get(tp->threads))) { silc_mutex_lock(t->lock); if (t->run) { silc_mutex_unlock(t->lock); continue; } /* Signal the thread to stop */ t->stop = TRUE; silc_cond_signal(t->thread_signal); silc_mutex_unlock(t->lock); silc_list_del(tp->free_threads, t); i--; if (!i) break; } silc_list_start(tp->threads); silc_mutex_unlock(tp->lock); }
SilcServerPending silc_server_command_pending(SilcServerThread thread, SilcUInt16 cmd_ident) { SilcServerPending pending; silc_mutex_lock(thread->server->lock); /* Check if pending already */ if (silc_hash_table_find(thread->server->pending_commands, SILC_32_TO_PTR(cmd_ident), NULL, (void **)&pending)) { pending->refcnt++; silc_mutex_unlock(thread->server->lock); return pending; } pending = silc_calloc(1, sizeof(*pending)); if (!pending) { silc_mutex_unlock(thread->server->lock); return NULL; } silc_fsm_event_init(&pending->wait_reply, &thread->fsm, 0); pending->refcnt = 1; pending->cmd_ident = cmd_ident; /* Add to pending commands hash table */ if (!silc_hash_table_add(thread->server->pending_commands, SILC_32_TO_PTR(cmd_ident), pending)) { silc_mutex_unlock(thread->server->lock); silc_free(pending); return NULL; } silc_mutex_unlock(thread->server->lock); return pending; }
void silc_server_command_pending_free(SilcServerThread thread, SilcServerPending pending) { silc_mutex_lock(thread->server->lock); pending->refcnt--; if (pending->refcnt > 0) { silc_mutex_unlock(thread->server->lock); return; } /* If command reply context set, free it also */ if (pending->reply) { pending->reply->pending = NULL; silc_server_command_free(pending->reply); } /* Remove from pending commands */ silc_hash_table_del_by_context(thread->server->pending_commands, SILC_32_TO_PTR(pending->cmd_ident), pending); silc_free(pending); silc_mutex_unlock(thread->server->lock); }
void silc_server_command_pending_signal(SilcServerCommand cmd) { SilcServerThread thread = cmd->thread; SilcServerPending pending = cmd->pending; if (!pending) return; silc_mutex_lock(thread->server->lock); /* Signal */ pending->reply = cmd; SILC_FSM_EVENT_SIGNAL(&pending->wait_reply); /* Remove from pending */ silc_hash_table_del_by_context(thread->server->pending_commands, SILC_32_TO_PTR(pending->cmd_ident), pending); silc_mutex_unlock(thread->server->lock); }
void silc_server_command_free(SilcServerCommand cmd) { SilcServerThread thread = cmd->thread; silc_mutex_lock(thread->server->lock); #if defined(SILC_DEBUG) /* Check for double free */ assert(cmd->packet != NULL); #endif /* SILC_DEBUG */ if (cmd->packet) silc_packet_free(cmd->packet); cmd->packet = NULL; if (cmd->pending) silc_server_command_pending_free(thread, cmd->pending); /* Put the packet back to freelist */ silc_list_add(thread->server->command_pool, cmd); silc_mutex_unlock(thread->server->lock); }
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; }
SilcBool silc_thread_pool_run(SilcThreadPool tp, SilcBool queuable, SilcSchedule schedule, SilcThreadPoolFunc run, void *run_context, SilcTaskCallback completion, void *completion_context) { SilcThreadPoolThread t, q; silc_mutex_lock(tp->lock); if (tp->destroy) { silc_mutex_unlock(tp->lock); silc_set_errno(SILC_ERR_NOT_VALID); return FALSE; } /* Get free thread */ silc_list_start(tp->free_threads); t = silc_list_get(tp->free_threads); if (!t || t->stop) { if (silc_list_count(tp->threads) + 1 > tp->max_threads) { /* Maximum threads reached */ if (!queuable) { silc_mutex_unlock(tp->lock); silc_set_errno(SILC_ERR_LIMIT); return FALSE; } /* User wants to queue this call until thread becomes free. Get a thread to assign this call. */ t = silc_list_get(tp->threads); if (!t) { /* List wraps around */ silc_list_start(tp->threads); t = silc_list_get(tp->threads); } silc_mutex_unlock(tp->lock); SILC_LOG_DEBUG(("Queue call %p, context %p in thread %p", run, run_context, t)); silc_mutex_lock(t->lock); /* Get free call context from the list */ silc_list_start(t->free_queue); q = silc_list_get(t->free_queue); if (!q) { q = silc_scalloc(tp->stack, 1, sizeof(*q)); if (!q) { silc_mutex_unlock(t->lock); return FALSE; } } else { silc_list_del(t->free_queue, q); } q->run = run; q->run_context = run_context; q->completion = completion; q->completion_context = completion_context; q->schedule = schedule; /* Add at the start of the list. It gets executed first. */ silc_list_insert(t->queue, NULL, q); silc_mutex_unlock(t->lock); return TRUE; } else { /* Create new thread */ t = silc_thread_pool_new_thread(tp); if (!t) { silc_mutex_unlock(tp->lock); return FALSE; } } } silc_list_del(tp->free_threads, t); silc_mutex_unlock(tp->lock); SILC_LOG_DEBUG(("Run call %p, context %p, thread %p", run, run_context, t)); silc_mutex_lock(t->lock); /* Mark this call to be executed in this thread */ t->run = run; t->run_context = run_context; t->completion = completion; t->completion_context = completion_context; t->schedule = schedule; /* Signal the thread */ silc_cond_signal(t->thread_signal); silc_mutex_unlock(t->lock); return TRUE; }