void silc_socket_stream_destroy(SilcStream stream) { SilcSocketStream socket_stream = stream; silc_socket_stream_close(socket_stream); silc_free(socket_stream->ip); silc_free(socket_stream->hostname); if (socket_stream->schedule) silc_schedule_task_del_by_fd(socket_stream->schedule, socket_stream->sock); if (socket_stream->qos) { silc_schedule_task_del_by_context(socket_stream->schedule, socket_stream->qos); if (socket_stream->qos->buffer) { memset(socket_stream->qos->buffer, 0, socket_stream->qos->read_limit_bytes); silc_free(socket_stream->qos->buffer); } silc_free(socket_stream->qos); } if (socket_stream->schedule) silc_schedule_wakeup(socket_stream->schedule); silc_free(socket_stream); }
static void *silc_net_gethostbyaddr_thread(void *context) { SilcNetResolveContext r = (SilcNetResolveContext)context; SilcSchedule schedule = r->schedule; char tmp[256]; if (silc_net_gethostbyaddr(r->input, tmp, sizeof(tmp))) r->result = strdup(tmp); silc_schedule_task_add(schedule, 0, silc_net_resolve_completion, r, 0, 1, SILC_TASK_TIMEOUT); silc_schedule_wakeup(schedule); return NULL; }
SilcBool silc_socket_stream_notifier(SilcStream stream, SilcSchedule schedule, SilcStreamNotifier callback, void *context) { SilcSocketStream socket_stream = stream; SILC_LOG_DEBUG(("Setting stream notifier callback")); socket_stream->notifier = callback; socket_stream->notifier_context = context; socket_stream->schedule = schedule; if (socket_stream->notifier && socket_stream->schedule) { /* Set the socket to non-blocking mode */ silc_net_set_socket_nonblock(socket_stream->sock); /* Add the socket to scheduler. Safe to call if already added. */ if (!silc_schedule_task_add_fd(socket_stream->schedule, socket_stream->sock, silc_socket_stream_io, socket_stream)) return FALSE; /* Initially set socket for reading */ if (!silc_schedule_set_listen_fd(socket_stream->schedule, socket_stream->sock, SILC_TASK_READ, FALSE)) return FALSE; } else if (socket_stream->schedule) { /* Unschedule the socket */ silc_schedule_unset_listen_fd(socket_stream->schedule, socket_stream->sock); silc_schedule_task_del_by_fd(socket_stream->schedule, socket_stream->sock); } if (socket_stream->schedule) silc_schedule_wakeup(socket_stream->schedule); return TRUE; }
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; }