Пример #1
0
void hlt_thread_queue_flush(hlt_thread_queue* queue, int writer)
{
    int block;

    batch* b = queue->writer_batches[writer];

    if ( ! ( b && b->write_pos ) )
        // Nothing to do.
        return;

    do {
        int i;

        _acquire_lock(queue, &i, 0, writer);
        ++queue->writer_stats[writer].locked;

        if ( ! queue->lock_block ) {
            block = 0;

            // If we have space in the queue, move our batch to the end of
            // the reader's pending queue.
            if ( queue->lock_num_pending < queue->max_batches || ! queue->max_batches ) {
                if ( queue->lock_pending_tail )
                    queue->lock_pending_tail->next = b;
                else
                    queue->lock_pending_head = b;

                queue->lock_pending_tail = b;

                ++queue->lock_num_pending;
                ++queue->writer_stats[writer].batches;

                // Can't write to this batch any longer.
                queue->writer_batches[writer] = 0;
            }
            else
                // Max number of pending batches reached, can't do anything right now.
                queue->lock_block = block = 1;
        }

        else
            // Oops, pending queue is completely filled up already. Need to
            // block.
            block = 1;

        _release_lock(queue, i, 0, writer);

        if ( block ) {
            ++queue->writer_stats[writer].blocked;
            // Sleep a tiny bit.
            // pthread_yield();
            hlt_util_nanosleep(1000);
        }

        pthread_testcancel();

    } while ( block );

    assert(! queue->writer_batches[writer]);
}
Пример #2
0
void hlt_thread_queue_terminate_writer(hlt_thread_queue* queue, int writer)
{
    int s;
    _acquire_lock(queue, &s, 0, writer);
    queue->lock_writers_terminated[writer] = 1;
    _release_lock(queue, s, 0, writer);

    hlt_thread_queue_flush(queue, writer);
}
Пример #3
0
static PyObject *
release_lock(PyObject *self)
{
    (void)self;
    if (!_release_lock()) {
        PyErr_SetString(PyExc_RuntimeError, "Thread lock count is zero");
        return NULL;
    }
    Py_RETURN_NONE;
}
Пример #4
0
static void _debug_print_queue(const char *prefix, hlt_thread_queue* q, int reader, int thread)
{
    int s;
    _acquire_lock(q, &s, reader, thread);

    fprintf(stderr, "%s: %p\n", prefix, q);
    for ( int i = 0; i < q->writers; i++ ) {
        fprintf(stderr, "  writer %d (elems %lu, terminated %d) * ", i, q->writer_num_written[i], q->lock_writers_terminated[i]);
        _debug_print_batch(q->writer_batches[i]);
    }

    fprintf(stderr, "  reader at %d (elems %lu, found terminated %d) * ", q->reader_pos, q->reader_num_read, q->reader_num_terminated);
    _debug_print_batch(q->reader_head);

    fprintf(stderr, "  pending (num %d / block %d) * ", q->lock_num_pending, q->lock_block);
    _debug_print_batch(q->lock_pending_head);

    _release_lock(q, s, reader, thread);
}
Пример #5
0
void* hlt_thread_queue_read(hlt_thread_queue* queue, int timeout)
{
    int block = (timeout == 0);

    timeout *= 1000; // Turn it into nanoseconds.

    while ( 1 ) {

        while ( queue->reader_head ) {
            // We still have stuff to do, so do it.

            if ( queue->need_flush )
                queue->need_flush = 0;

            batch* b = queue->reader_head;

            if ( queue->reader_pos < b->write_pos ) {
                // Still something in our current batch.
                ++queue->reader_stats->elems;
                ++queue->reader_num_read;
                return b->elems[queue->reader_pos++];
            }

            // Switch to next batch.
            batch* next = queue->reader_head->next;
            hlt_free(queue->reader_head);
            queue->reader_head = next;
            queue->reader_pos = 0;
            ++queue->reader_stats->batches;
        }

        pthread_testcancel();

        // Nothing left anymore, get a currently pending batch.

        int s;
        _acquire_lock(queue, &s, 1, 0);
        ++queue->reader_stats->locked;

        queue->reader_head = queue->lock_pending_head;
        queue->reader_pos = 0;
        queue->lock_pending_head = queue->lock_pending_tail = 0;
        queue->lock_num_pending = 0;
        queue->lock_block = 0;

        // Take the opportunity to check who has terminated.
        queue->reader_num_terminated = 0;

        for ( int i = 0; i < queue->writers; ++i ) {
            if ( queue->lock_writers_terminated[i] )
                ++queue->reader_num_terminated;
        }

        _release_lock(queue, s, 1, 0);

        if ( ! queue->reader_head ) {
            // Nothing was pending actually ...
            ++queue->reader_stats->blocked;
            queue->need_flush = 1;

            if ( timeout <= 0 && ! block )
                return 0;

            if ( hlt_thread_queue_terminated(queue) )
                return 0;

            // Sleep a tiny bit.
            // pthread_yield();
            hlt_util_nanosleep(1000);
            timeout -= 1000;
        }
    }

    // Can't be reached.
    assert(0);
}