예제 #1
0
/// The function that does thread work.
static void *iothread_worker(void *unused) {
    UNUSED(unused);
    struct spawn_request_t req;
    while (dequeue_spawn_request(&req)) {
        debug(5, "pthread %p dequeued", this_thread());

        // Perform the work
        req.handler();

        // If there's a completion handler, we have to enqueue it on the result queue.
        // Note we're using std::function's weirdo operator== here
        if (req.completion != nullptr) {
            // Enqueue the result, and tell the main thread about it.
            enqueue_thread_result(std::move(req));
            const char wakeup_byte = IO_SERVICE_RESULT_QUEUE;
            assert_with_errno(write_loop(s_write_pipe, &wakeup_byte, sizeof wakeup_byte) != -1);
        }
    }

    // We believe we have exhausted the thread request queue. We want to decrement
    // thread_count and exit. But it's possible that a request just came in. Furthermore,
    // it's possible that the main thread saw that thread_count is full, and decided to not
    // spawn a new thread, trusting in one of the existing threads to handle it. But we've already
    // committed to not handling anything else. Therefore, we have to decrement
    // the thread count under the lock, which we still hold. Likewise, the main thread must
    // check the value under the lock.
    int new_thread_count = --s_spawn_requests.acquire().value.thread_count;
    assert(new_thread_count >= 0);

    debug(5, "pthread %p exiting", this_thread());
    // We're done.
    return NULL;
}
예제 #2
0
/// The function that does thread work.
static void *iothread_worker(void *unused) {
    scoped_lock locker(s_spawn_queue_lock);
    struct SpawnRequest_t *req;
    while ((req = dequeue_spawn_request()) != NULL) {
        IOTHREAD_LOG fprintf(stderr, "pthread %p dequeued %p\n", this_thread(), req);
        // Unlock the queue while we execute the request.
        locker.unlock();

        // Perform the work.
        req->handlerResult = req->handler(req->context);

        // If there's a completion handler, we have to enqueue it on the result queue. Otherwise, we
        // can just delete the request!
        if (req->completionCallback == NULL) {
            delete req;
        } else {
            // Enqueue the result, and tell the main thread about it.
            enqueue_thread_result(req);
            const char wakeup_byte = IO_SERVICE_RESULT_QUEUE;
            VOMIT_ON_FAILURE(!write_loop(s_write_pipe, &wakeup_byte, sizeof wakeup_byte));
        }

        // Lock us up again.
        locker.lock();
    }

    // We believe we have exhausted the thread request queue. We want to decrement
    // s_active_thread_count and exit. But it's possible that a request just came in. Furthermore,
    // it's possible that the main thread saw that s_active_thread_count is full, and decided to not
    // spawn a new thread, trusting in one of the existing threads to handle it. But we've already
    // committed to not handling anything else. Therefore, we have to decrement
    // s_active_thread_count under the lock, which we still hold. Likewise, the main thread must
    // check the value under the lock.
    ASSERT_IS_LOCKED(s_spawn_queue_lock);
    assert(s_active_thread_count > 0);
    s_active_thread_count -= 1;

    IOTHREAD_LOG fprintf(stderr, "pthread %p exiting\n", this_thread());
    // We're done.
    return NULL;
}