Blame src/chan_test.c

rpm-build 4aa2fb
#undef __STRICT_ANSI__
rpm-build 4aa2fb
rpm-build 4aa2fb
#include <pthread.h>
rpm-build 4aa2fb
#include <stdio.h>
rpm-build 4aa2fb
#include <stdlib.h>
rpm-build 4aa2fb
#include <string.h>
rpm-build 4aa2fb
#include <unistd.h>
rpm-build 4aa2fb
rpm-build 4aa2fb
#include "chan.h"
rpm-build 4aa2fb
rpm-build 4aa2fb
rpm-build 4aa2fb
int passed = 0;
rpm-build 4aa2fb
rpm-build 4aa2fb
void assert_true(int expression, chan_t* chan, char* msg)
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    if (!expression)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        chan_dispose(chan);
rpm-build 4aa2fb
        fprintf(stderr, "Assertion failed: %s\n", msg);
rpm-build 4aa2fb
        exit(1);
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void pass()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    printf(".");
rpm-build 4aa2fb
    fflush(stdout);
rpm-build 4aa2fb
    passed++;
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void wait_for_reader(chan_t* chan)
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    for (;;)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        pthread_mutex_lock(&chan->m_mu);
rpm-build 4aa2fb
        int send = chan->r_waiting > 0;
rpm-build 4aa2fb
        pthread_mutex_unlock(&chan->m_mu);
rpm-build 4aa2fb
        if (send) break;
rpm-build 4aa2fb
        sched_yield();
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void wait_for_writer(chan_t* chan)
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    for (;;)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        pthread_mutex_lock(&chan->m_mu);
rpm-build 4aa2fb
        int recv = chan->w_waiting > 0;
rpm-build 4aa2fb
        pthread_mutex_unlock(&chan->m_mu);
rpm-build 4aa2fb
        if (recv) break;
rpm-build 4aa2fb
        sched_yield();
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_init_buffered()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    size_t size = 5;
rpm-build 4aa2fb
    chan_t* chan = chan_init(size);
rpm-build 4aa2fb
rpm-build 4aa2fb
    assert_true(chan->queue != NULL, chan, "Queue is NULL");
rpm-build 4aa2fb
    assert_true((size_t) chan->queue->capacity == size, chan, "Size is not 5");
rpm-build 4aa2fb
    assert_true(!chan->closed, chan, "Chan is closed");
rpm-build 4aa2fb
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_init_unbuffered()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan = chan_init(0);
rpm-build 4aa2fb
rpm-build 4aa2fb
    assert_true(chan->queue == NULL, chan, "Queue is not NULL");
rpm-build 4aa2fb
    assert_true(!chan->closed, chan, "Chan is closed");
rpm-build 4aa2fb
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_init()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    test_chan_init_buffered();
rpm-build 4aa2fb
    test_chan_init_unbuffered();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_close()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan = chan_init(0);
rpm-build 4aa2fb
rpm-build 4aa2fb
    assert_true(!chan->closed, chan, "Chan is closed");
rpm-build 4aa2fb
    assert_true(!chan_is_closed(chan), chan, "Chan is closed");
rpm-build 4aa2fb
    assert_true(chan_close(chan) == 0, chan, "Close failed");
rpm-build 4aa2fb
    assert_true(chan->closed, chan, "Chan is not closed");
rpm-build 4aa2fb
    assert_true(chan_close(chan) == -1, chan, "Close succeeded");
rpm-build 4aa2fb
    assert_true(chan_is_closed(chan), chan, "Chan is not closed");
rpm-build 4aa2fb
    
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_send_buffered()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan = chan_init(1);
rpm-build 4aa2fb
    void* msg = "foo";
rpm-build 4aa2fb
rpm-build 4aa2fb
    assert_true(chan_size(chan) == 0, chan, "Queue is not empty");
rpm-build 4aa2fb
    assert_true(chan_send(chan, msg) == 0, chan, "Send failed");
rpm-build 4aa2fb
    assert_true(chan_size(chan) == 1, chan, "Queue is empty");
rpm-build 4aa2fb
    
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void* receiver(void* chan)
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    void* msg;
rpm-build 4aa2fb
    chan_recv(chan, &msg;;
rpm-build 4aa2fb
    return NULL;
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_send_unbuffered()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan = chan_init(0);
rpm-build 4aa2fb
    void* msg = "foo";
rpm-build 4aa2fb
    pthread_t th;
rpm-build 4aa2fb
    pthread_create(&th, NULL, receiver, chan);
rpm-build 4aa2fb
rpm-build 4aa2fb
    wait_for_reader(chan);
rpm-build 4aa2fb
rpm-build 4aa2fb
    assert_true(chan_size(chan) == 0, chan, "Chan size is not 0");
rpm-build 4aa2fb
    assert_true(!chan->w_waiting, chan, "Chan has sender");
rpm-build 4aa2fb
    assert_true(chan_send(chan, msg) == 0, chan, "Send failed");
rpm-build 4aa2fb
    assert_true(!chan->w_waiting, chan, "Chan has sender");
rpm-build 4aa2fb
    assert_true(chan_size(chan) == 0, chan, "Chan size is not 0");
rpm-build 4aa2fb
rpm-build 4aa2fb
    pthread_join(th, NULL);
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_send()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    test_chan_send_buffered();
rpm-build 4aa2fb
    test_chan_send_unbuffered();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_recv_buffered()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan = chan_init(1);
rpm-build 4aa2fb
    void* msg = "foo";
rpm-build 4aa2fb
rpm-build 4aa2fb
    assert_true(chan_size(chan) == 0, chan, "Queue is not empty");
rpm-build 4aa2fb
    chan_send(chan, msg);
rpm-build 4aa2fb
    assert_true(chan_size(chan) == 1, chan, "Queue is empty");
rpm-build 4aa2fb
    void* received;
rpm-build 4aa2fb
    assert_true(chan_recv(chan, &received) == 0, chan, "Recv failed");
rpm-build 4aa2fb
    assert_true(msg == received, chan, "Messages are not equal");
rpm-build 4aa2fb
    assert_true(chan_size(chan) == 0, chan, "Queue is not empty");
rpm-build 4aa2fb
    
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void* sender(void* chan)
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_send(chan, "foo");
rpm-build 4aa2fb
    return NULL;
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_recv_unbuffered()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan = chan_init(0);
rpm-build 4aa2fb
    pthread_t th;
rpm-build 4aa2fb
    pthread_create(&th, NULL, sender, chan);
rpm-build 4aa2fb
rpm-build 4aa2fb
    assert_true(chan_size(chan) == 0, chan, "Chan size is not 0");
rpm-build 4aa2fb
    assert_true(!chan->r_waiting, chan, "Chan has reader");
rpm-build 4aa2fb
    void *msg;
rpm-build 4aa2fb
    assert_true(chan_recv(chan, &msg) == 0, chan, "Recv failed");
rpm-build 4aa2fb
    assert_true(strcmp(msg, "foo") == 0, chan, "Messages are not equal");
rpm-build 4aa2fb
    assert_true(!chan->r_waiting, chan, "Chan has reader");
rpm-build 4aa2fb
    assert_true(chan_size(chan) == 0, chan, "Chan size is not 0");
rpm-build 4aa2fb
rpm-build 4aa2fb
    pthread_join(th, NULL);
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_recv()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    test_chan_recv_buffered();
rpm-build 4aa2fb
    test_chan_recv_unbuffered();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_select_recv()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan1 = chan_init(0);
rpm-build 4aa2fb
    chan_t* chan2 = chan_init(1);
rpm-build 4aa2fb
    chan_t* chans[2] = {chan1, chan2};
rpm-build 4aa2fb
    void* recv;
rpm-build 4aa2fb
    void* msg = "foo";
rpm-build 4aa2fb
rpm-build 4aa2fb
    chan_send(chan2, msg);
rpm-build 4aa2fb
rpm-build 4aa2fb
    switch(chan_select(chans, 2, &recv, NULL, 0, NULL))
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        case 0:
rpm-build 4aa2fb
            chan_dispose(chan1);
rpm-build 4aa2fb
            chan_dispose(chan2);
rpm-build 4aa2fb
            fprintf(stderr, "Received on wrong channel\n");
rpm-build 4aa2fb
            exit(1);
rpm-build 4aa2fb
        case 1:
rpm-build 4aa2fb
            if (strcmp(recv, msg) != 0)
rpm-build 4aa2fb
            {
rpm-build 4aa2fb
                chan_dispose(chan1);
rpm-build 4aa2fb
                chan_dispose(chan2);
rpm-build 4aa2fb
                fprintf(stderr, "Messages are not equal\n");
rpm-build 4aa2fb
                exit(1);
rpm-build 4aa2fb
            }
rpm-build 4aa2fb
            recv = NULL;
rpm-build 4aa2fb
            break;
rpm-build 4aa2fb
        default:
rpm-build 4aa2fb
            chan_dispose(chan1);
rpm-build 4aa2fb
            chan_dispose(chan2);
rpm-build 4aa2fb
            fprintf(stderr, "Received on no channels\n");
rpm-build 4aa2fb
            exit(1);
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    pthread_t th;
rpm-build 4aa2fb
    pthread_create(&th, NULL, sender, chan1);
rpm-build 4aa2fb
    wait_for_writer(chan1);
rpm-build 4aa2fb
rpm-build 4aa2fb
    switch(chan_select(chans, 2, &recv, NULL, 0, NULL))
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        case 0:
rpm-build 4aa2fb
            if (strcmp(recv, "foo") != 0)
rpm-build 4aa2fb
            {
rpm-build 4aa2fb
                chan_dispose(chan1);
rpm-build 4aa2fb
                chan_dispose(chan2);
rpm-build 4aa2fb
                fprintf(stderr, "Messages are not equal\n");
rpm-build 4aa2fb
                exit(1);
rpm-build 4aa2fb
            }
rpm-build 4aa2fb
            recv = NULL;
rpm-build 4aa2fb
            break;
rpm-build 4aa2fb
        case 1:
rpm-build 4aa2fb
            chan_dispose(chan1);
rpm-build 4aa2fb
            chan_dispose(chan2);
rpm-build 4aa2fb
            fprintf(stderr, "Received on wrong channel\n");
rpm-build 4aa2fb
            exit(1);
rpm-build 4aa2fb
        default:
rpm-build 4aa2fb
            chan_dispose(chan1);
rpm-build 4aa2fb
            chan_dispose(chan2);
rpm-build 4aa2fb
            fprintf(stderr, "Received on no channels\n");
rpm-build 4aa2fb
            exit(1);
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    switch(chan_select(&chan2, 1, &msg, NULL, 0, NULL))
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        case 0:
rpm-build 4aa2fb
            chan_dispose(chan1);
rpm-build 4aa2fb
            chan_dispose(chan2);
rpm-build 4aa2fb
            fprintf(stderr, "Received on channel\n");
rpm-build 4aa2fb
            exit(1);
rpm-build 4aa2fb
        default:
rpm-build 4aa2fb
            break;
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    pthread_join(th, NULL);
rpm-build 4aa2fb
    chan_dispose(chan1);
rpm-build 4aa2fb
    chan_dispose(chan2);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_select_send()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan1 = chan_init(0);
rpm-build 4aa2fb
    chan_t* chan2 = chan_init(1);
rpm-build 4aa2fb
    chan_t* chans[2] = {chan1, chan2};
rpm-build 4aa2fb
    void* msg[] = {"foo", "bar"};
rpm-build 4aa2fb
rpm-build 4aa2fb
    switch(chan_select(NULL, 0, NULL, chans, 2, msg))
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        case 0:
rpm-build 4aa2fb
            chan_dispose(chan1);
rpm-build 4aa2fb
            chan_dispose(chan2);
rpm-build 4aa2fb
            fprintf(stderr, "Sent on wrong channel");
rpm-build 4aa2fb
            exit(1);
rpm-build 4aa2fb
        case 1:
rpm-build 4aa2fb
            break;
rpm-build 4aa2fb
        default:
rpm-build 4aa2fb
            chan_dispose(chan1);
rpm-build 4aa2fb
            chan_dispose(chan2);
rpm-build 4aa2fb
            fprintf(stderr, "Sent on no channels");
rpm-build 4aa2fb
            exit(1);
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    void* recv;
rpm-build 4aa2fb
    chan_recv(chan2, &recv;;
rpm-build 4aa2fb
    if (strcmp(recv, "bar") != 0)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        chan_dispose(chan1);
rpm-build 4aa2fb
        chan_dispose(chan2);
rpm-build 4aa2fb
        fprintf(stderr, "Messages are not equal");
rpm-build 4aa2fb
        exit(1);
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    chan_send(chan2, "foo");
rpm-build 4aa2fb
rpm-build 4aa2fb
    pthread_t th;
rpm-build 4aa2fb
    pthread_create(&th, NULL, receiver, chan1);
rpm-build 4aa2fb
    wait_for_reader(chan1);
rpm-build 4aa2fb
rpm-build 4aa2fb
    switch(chan_select(NULL, 0, NULL, chans, 2, msg))
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        case 0:
rpm-build 4aa2fb
            break;
rpm-build 4aa2fb
        case 1:
rpm-build 4aa2fb
            chan_dispose(chan1);
rpm-build 4aa2fb
            chan_dispose(chan2);
rpm-build 4aa2fb
            fprintf(stderr, "Sent on wrong channel");
rpm-build 4aa2fb
            exit(1);
rpm-build 4aa2fb
        default:
rpm-build 4aa2fb
            chan_dispose(chan1);
rpm-build 4aa2fb
            chan_dispose(chan2);
rpm-build 4aa2fb
            fprintf(stderr, "Sent on no channels");
rpm-build 4aa2fb
            exit(1);
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    switch(chan_select(NULL, 0, NULL, &chan1, 1, msg[0]))
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        case 0:
rpm-build 4aa2fb
            chan_dispose(chan1);
rpm-build 4aa2fb
            chan_dispose(chan2);
rpm-build 4aa2fb
            fprintf(stderr, "Sent on channel");
rpm-build 4aa2fb
            exit(1);
rpm-build 4aa2fb
        default:
rpm-build 4aa2fb
            break;
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    pthread_join(th, NULL);
rpm-build 4aa2fb
    chan_dispose(chan1);
rpm-build 4aa2fb
    chan_dispose(chan2);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_select()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    test_chan_select_recv();
rpm-build 4aa2fb
    test_chan_select_send();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_int()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan = chan_init(1);
rpm-build 4aa2fb
    int s = 12345, r = 0;
rpm-build 4aa2fb
    chan_send_int(chan, s);
rpm-build 4aa2fb
    chan_recv_int(chan, &r);
rpm-build 4aa2fb
    assert_true(s == r, chan, "Wrong value of int(12345)");
rpm-build 4aa2fb
rpm-build 4aa2fb
    int32_t s32 = 12345, r32 = 0;
rpm-build 4aa2fb
    chan_send_int32(chan, s32);
rpm-build 4aa2fb
    chan_recv_int32(chan, &r32);
rpm-build 4aa2fb
    assert_true(s32 == r32, chan, "Wrong value of int32(12345)");
rpm-build 4aa2fb
rpm-build 4aa2fb
    int64_t s64 = 12345, r64 = 0;
rpm-build 4aa2fb
    chan_send_int64(chan, s64);
rpm-build 4aa2fb
    chan_recv_int64(chan, &r64);
rpm-build 4aa2fb
    assert_true(s64 == r64, chan, "Wrong value of int64(12345)");
rpm-build 4aa2fb
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_double()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan = chan_init(1);
rpm-build 4aa2fb
    double s = 123.45, r = 0;
rpm-build 4aa2fb
    chan_send_double(chan, s);
rpm-build 4aa2fb
    chan_recv_double(chan, &r);
rpm-build 4aa2fb
    assert_true(s == r, chan, "Wrong value of double(123.45)");
rpm-build 4aa2fb
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_buf()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan = chan_init(1);
rpm-build 4aa2fb
    char s[256], r[256];
rpm-build 4aa2fb
    strcpy(s, "hello world");
rpm-build 4aa2fb
    chan_send_buf(chan, s, sizeof(s));
rpm-build 4aa2fb
    strcpy(s, "Hello World");
rpm-build 4aa2fb
    chan_recv_buf(chan, &r, sizeof(s));
rpm-build 4aa2fb
    assert_true(memcmp(s, r, sizeof(s)), chan, "Wrong value of buf");
rpm-build 4aa2fb
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_multi()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan = chan_init(5);
rpm-build 4aa2fb
    pthread_t th[100];
rpm-build 4aa2fb
    for (int i = 0; i < 50; ++i)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
       pthread_create(&th[i], NULL, sender, chan);
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    for (;;)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
       pthread_mutex_lock(&chan->m_mu);
rpm-build 4aa2fb
       int all_waiting = chan->w_waiting == 45;
rpm-build 4aa2fb
       pthread_mutex_unlock(&chan->m_mu);
rpm-build 4aa2fb
       if (all_waiting) break;
rpm-build 4aa2fb
       sched_yield();
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    for (int i = 50; i < 100; ++i)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
       pthread_create(&th[i], NULL, receiver, chan);
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    for (int i = 0; i < 100; ++i)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
       pthread_join(th[i], NULL);
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
void test_chan_multi2()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    chan_t* chan = chan_init(5);
rpm-build 4aa2fb
    pthread_t th[100];
rpm-build 4aa2fb
    for (int i = 0; i < 100; ++i)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        pthread_create(&th[i], NULL, receiver, chan);
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    for (;;)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
       pthread_mutex_lock(&chan->m_mu);
rpm-build 4aa2fb
       int all_waiting = chan->r_waiting == 100;
rpm-build 4aa2fb
       pthread_mutex_unlock(&chan->m_mu);
rpm-build 4aa2fb
       if (all_waiting) break;
rpm-build 4aa2fb
       sched_yield();
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    // Simulate 5 high-priority writing threads.
rpm-build 4aa2fb
    pthread_mutex_lock(&chan->m_mu);
rpm-build 4aa2fb
    for (int i = 0; i < 5; ++i)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        assert_true(0 == queue_add(chan->queue, "foo"), chan,
rpm-build 4aa2fb
            "Simulate writer thread");
rpm-build 4aa2fb
        pthread_cond_signal(&chan->r_cond); // wakeup reader
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    // Simulate 6th high-priority waiting writer.
rpm-build 4aa2fb
    assert_true(chan->queue->size == chan->queue->capacity, chan,
rpm-build 4aa2fb
        "6th writer has to wait");
rpm-build 4aa2fb
    chan->w_waiting++;
rpm-build 4aa2fb
    // Simulated writer must be woken up by reader.
rpm-build 4aa2fb
    pthread_cond_wait(&chan->w_cond, &chan->m_mu);
rpm-build 4aa2fb
    chan->w_waiting--;
rpm-build 4aa2fb
    pthread_mutex_unlock(&chan->m_mu);
rpm-build 4aa2fb
rpm-build 4aa2fb
    // Wake up other waiting reader.
rpm-build 4aa2fb
    for (int i = 5; i < 100; ++i)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        chan_send(chan, "foo");
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    for (int i = 0; i < 100; ++i)
rpm-build 4aa2fb
    {
rpm-build 4aa2fb
        pthread_join(th[i], NULL);
rpm-build 4aa2fb
    }
rpm-build 4aa2fb
rpm-build 4aa2fb
    chan_dispose(chan);
rpm-build 4aa2fb
    pass();
rpm-build 4aa2fb
}
rpm-build 4aa2fb
rpm-build 4aa2fb
int main()
rpm-build 4aa2fb
{
rpm-build 4aa2fb
    test_chan_init();
rpm-build 4aa2fb
    test_chan_close();
rpm-build 4aa2fb
    test_chan_send();
rpm-build 4aa2fb
    test_chan_recv();
rpm-build 4aa2fb
    test_chan_select();
rpm-build 4aa2fb
    test_chan_int();
rpm-build 4aa2fb
    test_chan_double();
rpm-build 4aa2fb
    test_chan_buf();
rpm-build 4aa2fb
    test_chan_multi();
rpm-build 4aa2fb
    test_chan_multi2();
rpm-build 4aa2fb
    printf("\n%d passed\n", passed);
rpm-build 4aa2fb
    return 0;
rpm-build 4aa2fb
}