/** * 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); }
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_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; }
static void iris_queue_real_close (IrisQueue *queue) { g_async_queue_lock (queue->priv->q); close_ul (queue); g_async_queue_unlock (queue->priv->q); }
/** * Cancel an idle request * @param request_id A request_id as returned by rs_io_idle_read_complete_file() */ void rs_io_idle_cancel(RSIoJob *job) { /* This behaves like rs_io_idle_cancel_class(), please see comments there */ RSIoJob *current_job; RSIoJob *marker_job = rs_io_job_new(); init(); g_async_queue_lock(queue); /* Put a marker in the queue, we will rotate the complete queue, so we have to know when we're around */ g_async_queue_push_unlocked(queue, marker_job); while((current_job = g_async_queue_pop_unlocked(queue))) { /* If current job matches marker, we're done */ if (current_job == marker_job) break; if (current_job != job) g_async_queue_push_unlocked(queue, current_job); } /* Make sure the queue is sorted */ g_async_queue_sort_unlocked(queue, queue_sort, NULL); g_async_queue_unlock(queue); g_object_unref(marker_job); }
/** * g_thread_pool_set_max_unused_threads: * @max_threads: maximal number of unused threads * * Sets the maximal number of unused threads to @max_threads. * If @max_threads is -1, no limit is imposed on the number * of unused threads. * * The default value is 2. */ void g_thread_pool_set_max_unused_threads (gint max_threads) { g_return_if_fail (max_threads >= -1); g_atomic_int_set (&max_unused_threads, max_threads); if (max_threads != -1) { max_threads -= g_atomic_int_get (&unused_threads); if (max_threads < 0) { g_atomic_int_set (&kill_unused_threads, -max_threads); g_atomic_int_inc (&wakeup_thread_serial); g_async_queue_lock (unused_thread_queue); do { g_async_queue_push_unlocked (unused_thread_queue, wakeup_thread_marker); } while (++max_threads); g_async_queue_unlock (unused_thread_queue); } } }
/** * Allocate and initialize a Zorp thread identified by a name, and * using the given thread function. * * @param[in] name name to identify this thread with * @param[in] func thread function * @param[in] arg pointer to pass to thread function * * @returns TRUE to indicate success **/ gboolean z_thread_new(gchar *name, GThreadFunc func, gpointer arg) { ZThread *self = g_new0(ZThread, 1); GError *error = NULL; static gint thread_id = 1; self->thread_id = thread_id++; self->func = func; self->arg = arg; strncpy(self->name, name, sizeof(self->name) - 1); g_async_queue_lock(queue); if (num_threads >= max_threads) { /*LOG This message reports that the maximal thread limit is reached. Try to increase the maximal thread limit. */ z_log(NULL, CORE_ERROR, 3, "Too many running threads, waiting for one to become free; num_threads='%d', max_threads='%d'", num_threads, max_threads); g_async_queue_push_unlocked(queue, self); g_async_queue_unlock(queue); } else { num_threads++; g_async_queue_ref_unlocked(queue); g_async_queue_unlock(queue); if (!g_thread_create_full(z_thread_func, self, max_stack_size, FALSE, TRUE, G_THREAD_PRIORITY_NORMAL, &error)) { /*LOG This message indicates that creating a new thread failed. It is likely that the system is running low on some resources or some limit is reached. */ z_log(NULL, CORE_ERROR, 2, "Error starting new thread; error='%s'", error->message); g_async_queue_lock(queue); num_threads--; g_async_queue_unlock(queue); return FALSE; } } return TRUE; }
/** * g_thread_pool_new: * @func: a function to execute in the threads of the new thread pool * @user_data: user data that is handed over to @func every time it * is called * @max_threads: the maximal number of threads to execute concurrently * in the new thread pool, -1 means no limit * @exclusive: should this thread pool be exclusive? * @error: return location for error, or %NULL * * This function creates a new thread pool. * * Whenever you call g_thread_pool_push(), either a new thread is * created or an unused one is reused. At most @max_threads threads * are running concurrently for this thread pool. @max_threads = -1 * allows unlimited threads to be created for this thread pool. The * newly created or reused thread now executes the function @func * with the two arguments. The first one is the parameter to * g_thread_pool_push() and the second one is @user_data. * * The parameter @exclusive determines whether the thread pool owns * all threads exclusive or shares them with other thread pools. * If @exclusive is %TRUE, @max_threads threads are started * immediately and they will run exclusively for this thread pool * until it is destroyed by g_thread_pool_free(). If @exclusive is * %FALSE, threads are created when needed and shared between all * non-exclusive thread pools. This implies that @max_threads may * not be -1 for exclusive thread pools. Besides, exclusive thread * pools are not affected by g_thread_pool_set_max_idle_time() * since their threads are never considered idle and returned to the * global pool. * * @error can be %NULL to ignore errors, or non-%NULL to report * errors. An error can only occur when @exclusive is set to %TRUE * and not all @max_threads threads could be created. * See #GThreadError for possible errors that may occur. * Note, even in case of error a valid #GThreadPool is returned. * * Returns: the new #GThreadPool */ GThreadPool * g_thread_pool_new (GFunc func, gpointer user_data, gint max_threads, gboolean exclusive, GError **error) { GRealThreadPool *retval; G_LOCK_DEFINE_STATIC (init); g_return_val_if_fail (func, NULL); g_return_val_if_fail (!exclusive || max_threads != -1, NULL); g_return_val_if_fail (max_threads >= -1, NULL); retval = g_new (GRealThreadPool, 1); retval->pool.func = func; retval->pool.user_data = user_data; retval->pool.exclusive = exclusive; retval->queue = g_async_queue_new (); g_cond_init (&retval->cond); retval->max_threads = max_threads; retval->num_threads = 0; retval->running = TRUE; retval->immediate = FALSE; retval->waiting = FALSE; retval->sort_func = NULL; retval->sort_user_data = NULL; G_LOCK (init); if (!unused_thread_queue) unused_thread_queue = g_async_queue_new (); G_UNLOCK (init); if (retval->pool.exclusive) { g_async_queue_lock (retval->queue); while (retval->num_threads < retval->max_threads) { GError *local_error = NULL; if (!g_thread_pool_start_thread (retval, &local_error)) { g_propagate_error (error, local_error); break; } } g_async_queue_unlock (retval->queue); } return (GThreadPool*) retval; }
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; }
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; }
static void _osync_queue_flush_messages(GAsyncQueue *queue) { OSyncMessage *message; osync_assert(queue); g_async_queue_lock(queue); while ((message = g_async_queue_try_pop_unlocked(queue))) osync_message_unref(message); g_async_queue_unlock(queue); }
static gboolean byzanz_queue_input_stream_ensure_input (ByzanzQueueInputStream *stream, GCancellable * cancellable, GError ** error) { GFile *file; if (stream->input_bytes >= BYZANZ_QUEUE_FILE_SIZE) { if (!byzanz_queue_input_stream_close_input (stream, cancellable, error)) return FALSE; stream->input = NULL; } if (stream->input != NULL) return TRUE; g_async_queue_lock (stream->queue->files); do { file = g_async_queue_try_pop_unlocked (stream->queue->files); if (file != NULL || stream->queue->output_closed) break; g_async_queue_unlock (stream->queue->files); if (!byzanz_queue_input_stream_wait (stream, cancellable, error)) return FALSE; g_async_queue_lock (stream->queue->files); } while (TRUE); g_async_queue_unlock (stream->queue->files); if (file == NULL) return TRUE; stream->input = G_INPUT_STREAM (g_file_read (file, cancellable, error)); g_file_delete (file, NULL, NULL); g_object_unref (file); return stream->input != NULL; }
static gpointer iris_queue_real_try_pop (IrisQueue *queue) { gpointer item; g_async_queue_lock (queue->priv->q); item = g_async_queue_try_pop_unlocked (queue->priv->q); 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; }
int e_msgport_fd (EMsgPort *msgport) { gint fd; g_return_val_if_fail (msgport != NULL, -1); g_async_queue_lock (msgport->queue); fd = msgport->pipe[0]; if (fd < 0 && e_pipe (msgport->pipe) == 0) fd = msgport->pipe[0]; g_async_queue_unlock (msgport->queue); return fd; }
PRFileDesc * e_msgport_prfd (EMsgPort *msgport) { PRFileDesc *prfd; g_return_val_if_fail (msgport != NULL, NULL); g_async_queue_lock (msgport->queue); prfd = msgport->prpipe[0]; if (prfd == NULL && e_prpipe (msgport->prpipe) == 0) prfd = msgport->prpipe[0]; g_async_queue_unlock (msgport->queue); return prfd; }
static gpointer iris_queue_real_timed_pop_or_close (IrisQueue *queue, GTimeVal *timeout) { gpointer item; g_async_queue_lock (queue->priv->q); 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); else if (item == NULL) close_ul (queue); g_async_queue_unlock (queue->priv->q); return item; }
void e_msgport_put (EMsgPort *msgport, EMsg *msg) { gint fd; #ifdef HAVE_NSS PRFileDesc *prfd; #endif g_return_if_fail (msgport != NULL); g_return_if_fail (msg != NULL); g_async_queue_lock (msgport->queue); msg->flags = 0; fd = msgport->pipe[1]; while (fd >= 0) { if (E_WRITE (fd, "E", 1) > 0) { msg->flags |= MSG_FLAG_SYNC_WITH_PIPE; break; } else if (!E_IS_STATUS_INTR ()) { g_warning ("%s: Failed to write to pipe: %s", G_STRFUNC, g_strerror (errno)); break; } } #ifdef HAVE_NSS prfd = msgport->prpipe[1]; while (prfd != NULL) { if (PR_Write (prfd, "E", 1) > 0) { msg->flags |= MSG_FLAG_SYNC_WITH_PR_PIPE; break; } else if (PR_GetError () != PR_PENDING_INTERRUPT_ERROR) { gchar *text = g_alloca (PR_GetErrorTextLength ()); PR_GetErrorText (text); g_warning ("%s: Failed to write to NSPR pipe: %s", G_STRFUNC, text); break; } } #endif g_async_queue_push_unlocked (msgport->queue, msg); g_async_queue_unlock (msgport->queue); }
/** * g_thread_pool_get_num_threads: * @pool: a #GThreadPool * * Returns the number of threads currently running in @pool. * * Returns: the number of threads currently running */ guint g_thread_pool_get_num_threads (GThreadPool *pool) { GRealThreadPool *real; guint retval; real = (GRealThreadPool*) pool; g_return_val_if_fail (real, 0); g_return_val_if_fail (real->running, 0); g_async_queue_lock (real->queue); retval = real->num_threads; g_async_queue_unlock (real->queue); return retval; }
static gboolean iris_queue_real_push (IrisQueue *queue, gpointer data) { gboolean is_open; g_return_val_if_fail (data != NULL, FALSE); g_async_queue_lock (queue->priv->q); is_open = g_atomic_int_get (&queue->priv->open); if (G_LIKELY (is_open)) g_async_queue_push_unlocked (queue->priv->q, data); g_async_queue_unlock (queue->priv->q); return is_open; }
/** * 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; }
/** * 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); }
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; }
EMsg * e_msgport_get (EMsgPort *msgport) { EMsg *msg; g_return_val_if_fail (msgport != NULL, NULL); g_async_queue_lock (msgport->queue); msg = g_async_queue_try_pop_unlocked (msgport->queue); if (msg != NULL && msg->flags & MSG_FLAG_SYNC_WITH_PIPE) msgport_sync_with_pipe (msgport->pipe[0]); #ifdef HAVE_NSS if (msg != NULL && msg->flags & MSG_FLAG_SYNC_WITH_PR_PIPE) msgport_sync_with_prpipe (msgport->prpipe[0]); #endif g_async_queue_unlock (msgport->queue); return msg; }
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++; }
/** * g_thread_pool_set_max_idle_time: * @interval: the maximum @interval (in milliseconds) * a thread can be idle * * This function will set the maximum @interval that a thread * waiting in the pool for new tasks can be idle for before * being stopped. This function is similar to calling * g_thread_pool_stop_unused_threads() on a regular timeout, * except this is done on a per thread basis. * * By setting @interval to 0, idle threads will not be stopped. * * The default value is 15000 (15 seconds). * * Since: 2.10 */ void g_thread_pool_set_max_idle_time (guint interval) { guint i; g_atomic_int_set (&max_idle_time, interval); i = g_atomic_int_get (&unused_threads); if (i > 0) { g_atomic_int_inc (&wakeup_thread_serial); g_async_queue_lock (unused_thread_queue); do { g_async_queue_push_unlocked (unused_thread_queue, wakeup_thread_marker); } while (--i); g_async_queue_unlock (unused_thread_queue); } }
static gboolean byzanz_queue_input_stream_close (GInputStream * input_stream, GCancellable * cancellable, GError ** error) { ByzanzQueueInputStream *stream = BYZANZ_QUEUE_INPUT_STREAM (input_stream); GFile *file; if (!byzanz_queue_input_stream_close_input (stream, cancellable, error)) return FALSE; g_async_queue_lock (stream->queue->files); stream->queue->input_closed = TRUE; file = g_async_queue_try_pop_unlocked (stream->queue->files); g_async_queue_unlock (stream->queue->files); while (file) { g_file_delete (file, NULL, NULL); file = g_async_queue_try_pop (stream->queue->files); } return TRUE; }
/** * This function wrapped around the real thread function logging two * events when the thread starts & stops * * @param[in] st thread state **/ static gpointer z_thread_func(gpointer st) { ZThread *self = (ZThread *) st; do { z_thread_func_core(self, NULL); self = NULL; g_async_queue_lock(queue); self = (ZThread *) g_async_queue_try_pop_unlocked(queue); if (!self) { num_threads--; g_async_queue_unref_and_unlock(queue); } else g_async_queue_unlock(queue); } while (self != NULL); return NULL; }
/** * g_thread_pool_set_sort_function: * @pool: a #GThreadPool * @func: the #GCompareDataFunc used to sort the list of tasks. * This function is passed two tasks. It should return * 0 if the order in which they are handled does not matter, * a negative value if the first task should be processed before * the second or a positive value if the second task should be * processed first. * @user_data: user data passed to @func * * Sets the function used to sort the list of tasks. This allows the * tasks to be processed by a priority determined by @func, and not * just in the order in which they were added to the pool. * * Note, if the maximum number of threads is more than 1, the order * that threads are executed cannot be guaranteed 100%. Threads are * scheduled by the operating system and are executed at random. It * cannot be assumed that threads are executed in the order they are * created. * * Since: 2.10 */ void g_thread_pool_set_sort_function (GThreadPool *pool, GCompareDataFunc func, gpointer user_data) { GRealThreadPool *real; real = (GRealThreadPool*) pool; g_return_if_fail (real); g_return_if_fail (real->running); g_async_queue_lock (real->queue); real->sort_func = func; real->sort_user_data = user_data; if (func) g_async_queue_sort_unlocked (real->queue, real->sort_func, real->sort_user_data); g_async_queue_unlock (real->queue); }
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 }
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; }