예제 #1
0
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);
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
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;
}