Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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);
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
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 */
}
Ejemplo n.º 8
0
void silc_rwlock_wrlock(SilcRwLock rwlock)
{
#ifdef SILC_THREADS
  if (rwlock) {
    silc_mutex_lock(rwlock->mutex);
    while (rwlock->readers > 0)
      silc_cond_wait(rwlock->cond, rwlock->mutex);
    rwlock->locked = TRUE;
  }
#endif /* SILC_THREADS */
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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);
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
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 */
}
Ejemplo n.º 13
0
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);
}
Ejemplo n.º 14
0
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;
}
Ejemplo n.º 15
0
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);
}
Ejemplo n.º 16
0
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);
}
Ejemplo n.º 17
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;
}
Ejemplo n.º 18
0
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;
}