static gpointer
g_thread_pool_wait_for_new_task (GRealThreadPool *pool)
{
  gpointer task = NULL;

  if (pool->running || (!pool->immediate &&
			g_async_queue_length_unlocked (pool->queue) > 0))
    {
      /* This thread pool is still active. */
      if (pool->num_threads > pool->max_threads && pool->max_threads != -1)
	{
	  /* This is a superfluous thread, so it goes to the global pool. */
	  DEBUG_MSG (("superfluous thread %p in pool %p.",
		      g_thread_self (), pool));
	}
      else if (pool->pool.exclusive)
	{
	  /* Exclusive threads stay attached to the pool. */
	  task = g_async_queue_pop_unlocked (pool->queue);

	  DEBUG_MSG (("thread %p in exclusive pool %p waits for task "
		      "(%d running, %d unprocessed).",
		      g_thread_self (), pool, pool->num_threads,
		      g_async_queue_length_unlocked (pool->queue)));
	}
      else
	{
	  /* A thread will wait for new tasks for at most 1/2
	   * second before going to the global pool.
	   */
	  GTimeVal end_time;

	  g_get_current_time (&end_time);
	  g_time_val_add (&end_time, G_USEC_PER_SEC / 2);	/* 1/2 second */

	  DEBUG_MSG (("thread %p in pool %p waits for up to a 1/2 second for task "
		      "(%d running, %d unprocessed).",
		      g_thread_self (), pool, pool->num_threads,
		      g_async_queue_length_unlocked (pool->queue)));

	  task = g_async_queue_timed_pop_unlocked (pool->queue, &end_time);
	}
    }
  else
    {
      /* This thread pool is inactive, it will no longer process tasks. */
      DEBUG_MSG (("pool %p not active, thread %p will go to global pool "
		  "(running: %s, immediate: %s, len: %d).",
		  pool, g_thread_self (),
		  pool->running ? "true" : "false",
		  pool->immediate ? "true" : "false",
		  g_async_queue_length_unlocked (pool->queue)));
    }

  return task;
}
Exemple #2
0
static void
player_av_set_position (Player *self, guint pos)
{
    PlayerAVPrivate *priv = PLAYER_AV (self)->priv;

    int stream = priv->astream;
    int64_t seek_target = av_rescale_q (AV_TIME_BASE * pos, AV_TIME_BASE_Q,
        priv->fctx->streams[stream]->time_base);

    if (!av_seek_frame (priv->fctx, stream, seek_target, 0)) {
        g_print ("It Failed\n");
    } else {
        g_print ("Seek OK?\n");
    }

    g_mutex_lock (priv->rp_mutex);
    g_async_queue_lock (priv->apq);
    g_async_queue_lock (priv->vpq);

    while (g_async_queue_length_unlocked (priv->apq) > 0) {
        AVPacket *packet = g_async_queue_pop_unlocked (priv->apq);
        av_free_packet (packet);
        av_free (packet);
    }

    while (g_async_queue_length_unlocked (priv->vpq) > 0) {
        AVPacket *packet = g_async_queue_pop_unlocked (priv->vpq);
        av_free_packet (packet);
        av_free (packet);
    }

    avcodec_flush_buffers (priv->actx);
    if (priv->vctx) {
        avcodec_flush_buffers (priv->vctx);
    }

    g_async_queue_unlock (priv->apq);
    g_async_queue_unlock (priv->vpq);
    g_mutex_unlock (priv->rp_mutex);

    switch (priv->state) {
        case PLAYER_STATE_PLAYING:
            break;
        case PLAYER_STATE_PAUSED:
        case PLAYER_STATE_STOPPED:
            break;
        default:
            g_print ("Can not change position in current state\n");
    };

//    g_signal_emit (self, signal_pos, 0, player_av_get_position (self));
    _player_emit_position_changed (PLAYER (self),
        player_av_get_position (self));
}
/**
 * g_thread_pool_free:
 * @pool: a #GThreadPool
 * @immediate: should @pool shut down immediately?
 * @wait_: should the function wait for all tasks to be finished?
 *
 * Frees all resources allocated for @pool.
 *
 * If @immediate is %TRUE, no new task is processed for
 * @pool. Otherwise @pool is not freed before the last task is
 * processed. Note however, that no thread of this pool is
 * interrupted, while processing a task. Instead at least all still
 * running threads can finish their tasks before the @pool is freed.
 *
 * If @wait_ is %TRUE, the functions does not return before all tasks
 * to be processed (dependent on @immediate, whether all or only the
 * currently running) are ready. Otherwise the function returns immediately.
 *
 * After calling this function @pool must not be used anymore. 
 **/
void
g_thread_pool_free (GThreadPool *pool,
		    gboolean     immediate,
		    gboolean     wait_)
{
  GRealThreadPool *real;

  real = (GRealThreadPool*) pool;

  g_return_if_fail (real);
  g_return_if_fail (real->running);

  /* If there's no thread allowed here, there is not much sense in
   * not stopping this pool immediately, when it's not empty 
   */
  g_return_if_fail (immediate || 
		    real->max_threads != 0 || 
		    g_async_queue_length (real->queue) == 0);

  g_async_queue_lock (real->queue);

  real->running = FALSE;
  real->immediate = immediate;
  real->waiting = wait_;

  if (wait_)
    {
      real->cond = g_cond_new ();

      while (g_async_queue_length_unlocked (real->queue) != -real->num_threads &&
	     !(immediate && real->num_threads == 0))
	g_cond_wait (real->cond, _g_async_queue_get_mutex (real->queue));
    }

  if (immediate || g_async_queue_length_unlocked (real->queue) == -real->num_threads)
    {
      /* No thread is currently doing something (and nothing is left
       * to process in the queue) 
       */
      if (real->num_threads == 0) 
	{
	  /* No threads left, we clean up */
	  g_async_queue_unlock (real->queue);
	  g_thread_pool_free_internal (real);
	  return;
	}

      g_thread_pool_wakeup_and_stop_all (real);
    }
  
  /* The last thread should cleanup the pool */
  real->waiting = FALSE; 
  g_async_queue_unlock (real->queue);
}
Exemple #4
0
/* Swallow CLOSE_TOKEN items */
static gpointer
handle_close_token_ul (IrisQueue *queue,
                       gpointer   item)
{
	gint remaining_items;

	if (item == NULL)
		return NULL;

	/* Filter close tokens. They must be the last items in the queue, so we can
	 * avoid filtering actual queue items that happen to be the same value.
	 */
	remaining_items = g_async_queue_length_unlocked (queue->priv->q) + 
	                  queue->priv->q->waiting_threads;

	g_warn_if_fail (remaining_items >= queue->priv->close_token_count -1);

	if ((queue->priv->close_token_count > 0) &&
	     remaining_items == queue->priv->close_token_count -1) {
		g_warn_if_fail (item == CLOSE_TOKEN);

		queue->priv->close_token_count --;
		return NULL;
	} else
		return item;
}
Exemple #5
0
/**
 * g_thread_pool_push:
 * @pool: a #GThreadPool
 * @data: a new task for @pool
 * @error: return location for error, or %NULL
 *
 * Inserts @data into the list of tasks to be executed by @pool.
 *
 * When the number of currently running threads is lower than the
 * maximal allowed number of threads, a new thread is started (or
 * reused) with the properties given to g_thread_pool_new().
 * Otherwise, @data stays in the queue until a thread in this pool
 * finishes its previous task and processes @data.
 *
 * @error can be %NULL to ignore errors, or non-%NULL to report
 * errors. An error can only occur when a new thread couldn't be
 * created. In that case @data is simply appended to the queue of
 * work to do.
 *
 * Before version 2.32, this function did not return a success status.
 *
 * Returns: %TRUE on success, %FALSE if an error occurred
 */
gboolean
g_thread_pool_push (GThreadPool  *pool,
                    gpointer      data,
                    GError      **error)
{
  GRealThreadPool *real;
  gboolean result;

  real = (GRealThreadPool*) pool;

  g_return_val_if_fail (real, FALSE);
  g_return_val_if_fail (real->running, FALSE);

  result = TRUE;

  g_async_queue_lock (real->queue);

  if (g_async_queue_length_unlocked (real->queue) >= 0)
    {
      /* No thread is waiting in the queue */
      GError *local_error = NULL;

      if (!g_thread_pool_start_thread (real, &local_error))
        {
          g_propagate_error (error, local_error);
          result = FALSE;
        }
    }

  g_thread_pool_queue_push_unlocked (real, data);
  g_async_queue_unlock (real->queue);

  return result;
}
Exemple #6
0
void chassis_event_add_with_timeout(chassis *chas, struct event *ev, struct timeval *tv) {
	chassis_event_op_t *op = chassis_event_op_new();
	gssize ret;

	op->type = CHASSIS_EVENT_OP_ADD;
	op->ev   = ev;
	chassis_event_op_set_timeout(op, tv);

    g_async_queue_push_unlocked(chas->event_queue, op);

    g_debug("%s: cal chassis_event_add_with_timeout, fd:%d, timeout sec:%d,usec:%d",
					G_STRLOC, chas->event_notify_fds[1],
					(int) tv->tv_sec, (int) tv->tv_usec);

	/* ping the event handler */
	if (1 != (ret = send(chas->event_notify_fds[1], C("."), 0))) {
		int last_errno; 

		last_errno = errno;

        g_debug("%s: cal chassis_event_add_with_timeout, fd:%d errno:%d",
					G_STRLOC, chas->event_notify_fds[1], last_errno);

		switch (last_errno) {
		case EAGAIN:
		case E_NET_WOULDBLOCK:
			/* that's fine ... */
			g_debug("%s: send() to event-notify-pipe failed: %s (len = %d)",
					G_STRLOC,
					g_strerror(errno),
					g_async_queue_length_unlocked(chas->event_queue));
			break;
		default:
			g_critical("%s: send() to event-notify-pipe failed: %s (len = %d)",
					G_STRLOC,
					g_strerror(errno),
					g_async_queue_length_unlocked(chas->event_queue));
			break;
		}
	}
}
Exemple #7
0
static gboolean
g_thread_pool_start_thread (GRealThreadPool  *pool,
                            GError          **error)
{
  gboolean success = FALSE;

  if (pool->num_threads >= pool->max_threads && pool->max_threads != -1)
    /* Enough threads are already running */
    return TRUE;

  g_async_queue_lock (unused_thread_queue);

  if (g_async_queue_length_unlocked (unused_thread_queue) < 0)
    {
      g_async_queue_push_unlocked (unused_thread_queue, pool);
      success = TRUE;
    }

  g_async_queue_unlock (unused_thread_queue);

  if (!success)
    {
      GThread *thread;

      /* No thread was found, we have to start a new one */

      G_LOCK (threads);
      while (finished_threads != NULL)
        {
          thread = finished_threads->data;
          finished_threads = g_slist_delete_link (finished_threads,
                                                  finished_threads);
          G_UNLOCK (threads);
          g_thread_join (thread);
          G_LOCK (threads);
        }

      thread = g_thread_try_new ("pool", g_thread_pool_thread_proxy, pool, error);
      if (thread != NULL)
        active_threads = g_slist_prepend (active_threads, thread);
      G_UNLOCK (threads);

      if (thread == NULL)
        return FALSE;
  }

  /* See comment in g_thread_pool_thread_proxy as to why this is done
   * here and not there
   */
  pool->num_threads++;

  return TRUE;
}
Exemple #8
0
/**
 * g_thread_pool_set_max_threads:
 * @pool: a #GThreadPool
 * @max_threads: a new maximal number of threads for @pool,
 *     or -1 for unlimited
 * @error: return location for error, or %NULL
 *
 * Sets the maximal allowed number of threads for @pool.
 * A value of -1 means that the maximal number of threads
 * is unlimited. If @pool is an exclusive thread pool, setting
 * the maximal number of threads to -1 is not allowed.
 *
 * Setting @max_threads to 0 means stopping all work for @pool.
 * It is effectively frozen until @max_threads is set to a non-zero
 * value again.
 *
 * A thread is never terminated while calling @func, as supplied by
 * g_thread_pool_new(). Instead the maximal number of threads only
 * has effect for the allocation of new threads in g_thread_pool_push().
 * A new thread is allocated, whenever the number of currently
 * running threads in @pool is smaller than the maximal number.
 *
 * @error can be %NULL to ignore errors, or non-%NULL to report
 * errors. An error can only occur when a new thread couldn't be
 * created.
 *
 * Before version 2.32, this function did not return a success status.
 *
 * Returns: %TRUE on success, %FALSE if an error occurred
 */
gboolean
g_thread_pool_set_max_threads (GThreadPool  *pool,
                               gint          max_threads,
                               GError      **error)
{
  GRealThreadPool *real;
  gint to_start;
  gboolean result;

  real = (GRealThreadPool*) pool;

  g_return_val_if_fail (real, FALSE);
  g_return_val_if_fail (real->running, FALSE);
  g_return_val_if_fail (!real->pool.exclusive || max_threads != -1, FALSE);
  g_return_val_if_fail (max_threads >= -1, FALSE);

  result = TRUE;

  g_async_queue_lock (real->queue);

  real->max_threads = max_threads;

  if (pool->exclusive)
    to_start = real->max_threads - real->num_threads;
  else
    to_start = g_async_queue_length_unlocked (real->queue);

  for ( ; to_start > 0; to_start--)
    {
      GError *local_error = NULL;

      if (!g_thread_pool_start_thread (real, &local_error))
        {
          g_propagate_error (error, local_error);
          result = FALSE;
          break;
        }
    }

  g_async_queue_unlock (real->queue);

  return result;
}
Exemple #9
0
static gpointer
iris_queue_real_timed_pop (IrisQueue *queue,
                           GTimeVal  *timeout)
{
	gpointer item;

	g_async_queue_lock (queue->priv->q);
	if (g_atomic_int_get (&queue->priv->open) == FALSE &&
	    g_async_queue_length_unlocked (queue->priv->q) <= 0) {
		g_async_queue_unlock (queue->priv->q);
		return NULL;
	}

	item = g_async_queue_timed_pop_unlocked (queue->priv->q, timeout);

	if (g_atomic_int_get (&queue->priv->open) == FALSE)
		item = handle_close_token_ul (queue, item);
	g_async_queue_unlock (queue->priv->q);

	return item;
}
/**
 * g_thread_pool_push:
 * @pool: a #GThreadPool
 * @data: a new task for @pool
 * @error: return location for error
 * 
 * Inserts @data into the list of tasks to be executed by @pool. When
 * the number of currently running threads is lower than the maximal
 * allowed number of threads, a new thread is started (or reused) with
 * the properties given to g_thread_pool_new (). Otherwise @data stays
 * in the queue until a thread in this pool finishes its previous task
 * and processes @data. 
 *
 * @error can be %NULL to ignore errors, or non-%NULL to report
 * errors. An error can only occur when a new thread couldn't be
 * created. In that case @data is simply appended to the queue of work
 * to do.  
 **/
void 
g_thread_pool_push (GThreadPool  *pool,
		    gpointer      data,
		    GError      **error)
{
  GRealThreadPool *real;

  real = (GRealThreadPool*) pool;

  g_return_if_fail (real);
  g_return_if_fail (real->running);

  g_async_queue_lock (real->queue);

  if (g_async_queue_length_unlocked (real->queue) >= 0)
    /* No thread is waiting in the queue */
    g_thread_pool_start_thread (real, error);

  g_thread_pool_queue_push_unlocked (real, data);
  g_async_queue_unlock (real->queue);
}
Exemple #11
0
static gboolean
g_thread_pool_start_thread (GRealThreadPool  *pool,
                            GError          **error)
{
  gboolean success = FALSE;

  if (pool->num_threads >= pool->max_threads && pool->max_threads != -1)
    /* Enough threads are already running */
    return TRUE;

  g_async_queue_lock (unused_thread_queue);

  if (g_async_queue_length_unlocked (unused_thread_queue) < 0)
    {
      g_async_queue_push_unlocked (unused_thread_queue, pool);
      success = TRUE;
    }

  g_async_queue_unlock (unused_thread_queue);

  if (!success)
    {
      GThread *thread;

      /* No thread was found, we have to start a new one */
      thread = g_thread_try_new ("pool", g_thread_pool_thread_proxy, pool, error);

      if (thread == NULL)
        return FALSE;

      g_thread_unref (thread);
    }

  /* See comment in g_thread_pool_thread_proxy as to why this is done
   * here and not there
   */
  pool->num_threads++;

  return TRUE;
}
static void
g_thread_pool_start_thread (GRealThreadPool  *pool, 
			    GError          **error)
{
  gboolean success = FALSE;
  
  if (pool->num_threads >= pool->max_threads && pool->max_threads != -1)
    /* Enough threads are already running */
    return;

  g_async_queue_lock (unused_thread_queue);

  if (g_async_queue_length_unlocked (unused_thread_queue) < 0)
    {
      g_async_queue_push_unlocked (unused_thread_queue, pool);
      success = TRUE;
    }

  g_async_queue_unlock (unused_thread_queue);

  if (!success)
    {
      GError *local_error = NULL;
      /* No thread was found, we have to start a new one */
      g_thread_create (g_thread_pool_thread_proxy, pool, FALSE, &local_error);
      
      if (local_error)
	{
	  g_propagate_error (error, local_error);
	  return;
	}
    }

  /* See comment in g_thread_pool_thread_proxy as to why this is done
   * here and not there
   */
  pool->num_threads++;
}
Exemple #13
0
void nids_pcap_handler(u_char * par, struct pcap_pkthdr *hdr, u_char * data)
{
    u_char *data_aligned;
#ifdef HAVE_LIBGTHREAD_2_0
    struct cap_queue_item *qitem;
#endif
#ifdef DLT_IEEE802_11
    unsigned short fc;
    int linkoffset_tweaked_by_prism_code = 0;
#endif

    /*
     * Check for savagely closed TCP connections. Might
     * happen only when nids_params.tcp_workarounds is non-zero;
     * otherwise nids_tcp_timeouts is always NULL.
     */
    if (NULL != nids_tcp_timeouts)
      tcp_check_timeouts(&hdr->ts);

    nids_last_pcap_header = hdr;
    nids_last_pcap_data = data;
    (void)par; /* warnings... */
    switch (linktype) {
    case DLT_EN10MB:
	if (hdr->caplen < 14)
	    return;
	/* Only handle IP packets and 802.1Q VLAN tagged packets below. */
	if (data[12] == 8 && data[13] == 0) {
	    /* Regular ethernet */
	    nids_linkoffset = 14;
	} else if (data[12] == 0x81 && data[13] == 0) {
	    /* Skip 802.1Q VLAN and priority information */
	    nids_linkoffset = 18;
	} else
	    /* non-ip frame */
	    return;
	break;
#ifdef DLT_PRISM_HEADER
#ifndef DLT_IEEE802_11
#error DLT_PRISM_HEADER is defined, but DLT_IEEE802_11 is not ???
#endif
    case DLT_PRISM_HEADER:
	nids_linkoffset = 144; //sizeof(prism2_hdr);
	linkoffset_tweaked_by_prism_code = 1;
        //now let DLT_IEEE802_11 do the rest
#endif
#ifdef DLT_IEEE802_11
    case DLT_IEEE802_11:
	/* I don't know why frame control is always little endian, but it 
	 * works for tcpdump, so who am I to complain? (wam)
	 */
	if (!linkoffset_tweaked_by_prism_code)
		nids_linkoffset = 0;
	fc = EXTRACT_LE_16BITS(data + nids_linkoffset);
	if (FC_TYPE(fc) != T_DATA || FC_WEP(fc)) {
	    return;
	}
	if (FC_TO_DS(fc) && FC_FROM_DS(fc)) {
	    /* a wireless distribution system packet will have another
	     * MAC addr in the frame
	     */
	    nids_linkoffset += 30;
	} else {
	    nids_linkoffset += 24;
	}
	if (hdr->len < nids_linkoffset + LLC_FRAME_SIZE)
	    return;
	if (ETHERTYPE_IP !=
	    EXTRACT_16BITS(data + nids_linkoffset + LLC_OFFSET_TO_TYPE_FIELD)) {
	    /* EAP, LEAP, and other 802.11 enhancements can be 
	     * encapsulated within a data packet too.  Look only at
	     * encapsulated IP packets (Type field of the LLC frame).
	     */
	    return;
	}
	nids_linkoffset += LLC_FRAME_SIZE;
	break;
#endif
    default:;
    }
    if (hdr->caplen < nids_linkoffset)
	return;

/*
* sure, memcpy costs. But many EXTRACT_{SHORT, LONG} macros cost, too. 
* Anyway, libpcap tries to ensure proper layer 3 alignment (look for
* handle->offset in pcap sources), so memcpy should not be called.
*/
#ifdef LBL_ALIGN
    if ((unsigned long) (data + nids_linkoffset) & 0x3) {
	data_aligned = alloca(hdr->caplen - nids_linkoffset + 4);
	data_aligned -= (unsigned long) data_aligned % 4;
	memcpy(data_aligned, data + nids_linkoffset, hdr->caplen - nids_linkoffset);
    } else 
#endif
  data_aligned = data + nids_linkoffset;

 #ifdef HAVE_LIBGTHREAD_2_0
     if(nids_params.multiproc) { 
        /* 
         * Insert received fragment into the async capture queue.
         * We hope that the overhead of memcpy 
         * will be saturated by the benefits of SMP - mcree
         */
        qitem=malloc(sizeof(struct cap_queue_item));
        if (qitem && (qitem->data=malloc(hdr->caplen - nids_linkoffset))) {
          qitem->caplen=hdr->caplen - nids_linkoffset;
          memcpy(qitem->data,data_aligned,qitem->caplen);
          g_async_queue_lock(cap_queue);
          /* ensure queue does not overflow */
          if(g_async_queue_length_unlocked(cap_queue) > nids_params.queue_limit) {
	    /* queue limit reached: drop packet - should we notify user via syslog? */
	    free(qitem->data);
	    free(qitem);
	    } else {
	    /* insert packet to queue */
	    g_async_queue_push_unlocked(cap_queue,qitem);
          }
          g_async_queue_unlock(cap_queue);
	}
     } else { /* user requested simple passthru - no threading */
        call_ip_frag_procs(data_aligned,hdr->caplen - nids_linkoffset, &hdr->ts);
     }
 #else
     call_ip_frag_procs(data_aligned,hdr->caplen - nids_linkoffset, &hdr->ts);
 #endif
}
Exemple #14
0
static gpointer
g_thread_pool_thread_proxy (gpointer data)
{
  GRealThreadPool *pool;

  pool = data;

  DEBUG_MSG (("thread %p started for pool %p.", g_thread_self (), pool));

  g_async_queue_lock (pool->queue);

  while (TRUE)
    {
      gpointer task;

      task = g_thread_pool_wait_for_new_task (pool);
      if (task)
        {
          if (pool->running || !pool->immediate)
            {
              /* A task was received and the thread pool is active,
               * so execute the function.
               */
              g_async_queue_unlock (pool->queue);
              DEBUG_MSG (("thread %p in pool %p calling func.",
                          g_thread_self (), pool));
              pool->pool.func (task, pool->pool.user_data);
              g_async_queue_lock (pool->queue);
            }
        }
      else
        {
          /* No task was received, so this thread goes to the global pool. */
          gboolean free_pool = FALSE;

          DEBUG_MSG (("thread %p leaving pool %p for global pool.",
                      g_thread_self (), pool));
          pool->num_threads--;

          if (!pool->running)
            {
              if (!pool->waiting)
                {
                  if (pool->num_threads == 0)
                    {
                      /* If the pool is not running and no other
                       * thread is waiting for this thread pool to
                       * finish and this is the last thread of this
                       * pool, free the pool.
                       */
                      free_pool = TRUE;
                    }
                  else
                    {
                      /* If the pool is not running and no other
                       * thread is waiting for this thread pool to
                       * finish and this is not the last thread of
                       * this pool and there are no tasks left in the
                       * queue, wakeup the remaining threads.
                       */
                      if (g_async_queue_length_unlocked (pool->queue) ==
                          - pool->num_threads)
                        g_thread_pool_wakeup_and_stop_all (pool);
                    }
                }
              else if (pool->immediate ||
                       g_async_queue_length_unlocked (pool->queue) <= 0)
                {
                  /* If the pool is not running and another thread is
                   * waiting for this thread pool to finish and there
                   * are either no tasks left or the pool shall stop
                   * immediately, inform the waiting thread of a change
                   * of the thread pool state.
                   */
                  g_cond_broadcast (&pool->cond);
                }
            }

          g_async_queue_unlock (pool->queue);

          if (free_pool)
            g_thread_pool_free_internal (pool);

          if ((pool = g_thread_pool_wait_for_new_pool ()) == NULL)
            break;

          g_async_queue_lock (pool->queue);

          DEBUG_MSG (("thread %p entering pool %p from global pool.",
                      g_thread_self (), pool));

          /* pool->num_threads++ is not done here, but in
           * g_thread_pool_start_thread to make the new started
           * thread known to the pool before itself can do it.
           */
        }
    }

  return NULL;
}