示例#1
0
文件: main.c 项目: Sovietaced/indigo
int main(int argc, char* argv[])
{
    int cxn_id;
    int idx;
    ind_soc_config_t config; /* Currently ignored */

    INDIGO_MEM_CLEAR(&config, sizeof(config));
    OK(ind_soc_init(&config));

    OK(ind_cxn_init(&cm_config));

    OK(indigo_cxn_status_change_register(cxn_status_change, NULL));

    OK(ind_cxn_enable_set(1));
    INDIGO_ASSERT((cxn_id = setup_cxn()) >= 0);

    for (idx = 1; idx < 5; idx++) {
        printf("run %d\n", idx);
        OK(ind_soc_select_and_run(2000));
    }

    /* Now remove and add the cxn a few times */
    for (idx = 1; idx < 5; idx++) {
        OK(indigo_cxn_connection_remove(cxn_id));
        INDIGO_ASSERT((cxn_id = setup_cxn()) >= 0);
    }

    OK(indigo_cxn_connection_remove(cxn_id));

    OK(ind_cxn_enable_set(0));
    OK(ind_cxn_finish());

    return 0;
}
示例#2
0
static void
socket_callback(
    int socket_id,
    void *cookie,
    int read_ready,
    int write_ready,
    int error_seen)
{
    struct sock_counters *counters = cookie;
    printf("Socket callback called: id %d. rd %d. wr %d. er %d\n",
           socket_id, read_ready, write_ready, error_seen);
    INDIGO_ASSERT(!error_seen);

    if (write_ready) {
        counters->write++;
        if (write(socket_id, "x", 1) != 1) {
            perror("write");
            abort();
        }
        ind_soc_data_out_clear(socket_id);
    }

    if (read_ready) {
        char buf;
        counters->read++;
        if (read(socket_id, &buf, 1) != 1) {
            perror("read");
            abort();
        }
        INDIGO_ASSERT(buf == 'x');
    }
}
示例#3
0
indigo_error_t
ft_hash_flow_delete(ft_instance_t ft, ft_entry_t *entry, int make_callback)
{
    INDIGO_ASSERT(ft->magic == FT_HASH_MAGIC_NUMBER);

    LOG_TRACE("Delete rsn %d flow " INDIGO_FLOW_ID_PRINTF_FORMAT,
              entry->removed_reason, entry->id);

    if (entry->id == INDIGO_FLOW_ID_INVALID) {
        LOG_ERROR("Deleting invalid flow table entry");
        return INDIGO_ERROR_UNKNOWN;
    }

    if (make_callback && ft->config.entry_deleted_cb) {
        ft->config.entry_deleted_cb(ft, entry, ft->config.deleted_cookie);
    }

    /* Unlink from hash lists; clear entry; put it on the free list */
    ft_entry_unlink(ft, entry);
    ft_entry_clear(ft, entry);

    INDIGO_ASSERT(entry->state == FT_FLOW_STATE_FREE);
    list_push(&ft->free_list, &entry->table_links);
    ft->status.current_count -= 1;
    ft->status.deletes += 1;

    return INDIGO_ERROR_NONE;
}
示例#4
0
static void
process_flow_removal(ft_entry_t *entry,
                     indigo_fi_flow_stats_t *final_stats,
                     indigo_fi_flow_removed_t reason)
{
    indigo_error_t rv;

    if (entry->flags & OF_FLOW_MOD_FLAG_SEND_FLOW_REM) {
        /* See OF spec 1.0.1, section 3.5, page 6 */
        if (reason != INDIGO_FLOW_REMOVED_OVERWRITE) {
            if (final_stats != NULL) {
                INDIGO_ASSERT(final_stats->flow_id == entry->id);
                entry->packets = final_stats->packets;
                entry->bytes = final_stats->bytes;
            } else {
                entry->packets = (uint64_t)-1;
                entry->bytes = (uint64_t)-1;
            }

            send_flow_removed_message(entry, reason);
        }
    }

    rv = ft_delete(ind_core_ft, entry);
    if (rv != INDIGO_ERROR_NONE) {
        LOG_ERROR("Error deleting flow from state mgr. id: "
                  INDIGO_FLOW_ID_PRINTF_FORMAT,
                  INDIGO_FLOW_ID_PRINTF_ARG(entry->id));
    }
    LOG_TRACE("Flow table now has %d entries",
              FT_STATUS(ind_core_ft)->current_count);
}
示例#5
0
文件: main.c 项目: amertahir/indigo
static void
socket_callback(
    int socket_id,
    void *cookie,
    int read_ready,
    int write_ready,
    int error_seen)
{
    char buf[2048];
    int bytes_read;

    printf("Socket callback called: id %d. rd %d. wr %d. er %d\n",
           socket_id, read_ready, write_ready, error_seen);
    socket_called = 1;
    if (write_ready) {
        sock_write_seen = 1;
        send(socket_id, "x", 1, MSG_DONTWAIT);
        ind_soc_data_out_clear(socket_id);
    }
    if (read_ready) {
        printf("Reading from socket %d\n", socket_id);
        bytes_read = read(socket_id, buf, 2048);
        printf("Read in %d bytes\n", bytes_read);
        sock_read_seen = 1;
        ind_soc_data_out_ready(socket_id);
    }
    INDIGO_ASSERT(!error_seen);
}
示例#6
0
int
main(int argc, char* argv[])
{
    INDIGO_ASSERT(1==1);
    AIM_LOG_INFO("Okay.");
    return 0;
}
示例#7
0
static void
test_timer_mgmt(void)
{
    /* Should be able to register a timer */
    INDIGO_ASSERT(ind_soc_timer_event_register(
                      timer_callback, (void*)1, 10) == 0);

    /* Should be able to re-register a timer */
    INDIGO_ASSERT(ind_soc_timer_event_register(
                      timer_callback, (void*)1, 100) == 0);

    /* Should be able to unregister a timer */
    INDIGO_ASSERT(ind_soc_timer_event_unregister(
                      timer_callback, (void*)1) == 0);

    /* Should not be able to unregister a timer twice */
    INDIGO_ASSERT(ind_soc_timer_event_unregister(
                      timer_callback, (void*)1) < 0);

    /* Should not be able to unregister a NULL callback */
    INDIGO_ASSERT(ind_soc_timer_event_unregister(
                      NULL, (void*)1) < 0);

    /* Should be able to register and unregister a bunch of timers */
    {
        int i, j;

        for (i = 0; 1; i++) {
            indigo_error_t err = ind_soc_timer_event_register(
                                     timer_callback, (void *)(uintptr_t)i, 100);
            if (err < 0) {
                INDIGO_ASSERT(err == INDIGO_ERROR_RESOURCE);
                break;
            }
        }

        for (j = 0; 1; j++) {
            indigo_error_t err = ind_soc_timer_event_unregister(
                                     timer_callback, (void *)(uintptr_t)j);
            if (err < 0) {
                INDIGO_ASSERT(err == INDIGO_ERROR_NOT_FOUND);
                break;
            }
        }

        INDIGO_ASSERT(i == j);
        INDIGO_ASSERT(i >= 16);
    }
}
示例#8
0
static void
test_immediate_timer(void)
{
    int count = 0;
    INDIGO_ASSERT(ind_soc_timer_event_register(
                      timer_callback, &count, IND_SOC_TIMER_IMMEDIATE) == 0);

    /* Should run immediately */
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(count == 1);

    /* Should be unregistered after firing */
    count = 0;
    ind_soc_select_and_run(100);
    INDIGO_ASSERT(count == 0);

    /* Should be unregistered after firing */
    INDIGO_ASSERT(ind_soc_timer_event_unregister(timer_callback, &count) < 0);
}
示例#9
0
文件: main.c 项目: amertahir/indigo
int
main(int argc, char* argv[])
{
    ind_soc_config_t config = {0};
    int fds[2];

    printf("Init returned %d\n", ind_soc_init(&config));

    /* Should be called once */
    ind_soc_timer_event_register(timer_callback, NULL,
                                 IND_SOC_TIMER_IMMEDIATE);
    ind_soc_select_and_run(10);
    INDIGO_ASSERT(timer_called);
    timer_called = 0;
    ind_soc_select_and_run(1000);
    INDIGO_ASSERT(!timer_called);

    ind_soc_timer_event_register(timer_callback, NULL, 100);
    ind_soc_select_and_run(1000);
    INDIGO_ASSERT(timer_called);

    timer_called = 0;
    ind_soc_timer_event_register(timer_callback_repeat, NULL, 100);
    ind_soc_select_and_run(1000);
    INDIGO_ASSERT(timer_called >= 9);
    ind_soc_timer_event_unregister(timer_callback_repeat, NULL);

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
        perror("socketpair");
        abort();
    }

    INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, NULL) == 0);
    INDIGO_ASSERT(ind_soc_socket_register(fds[1], socket_callback, NULL) == 0);
    ind_soc_data_out_ready(fds[0]);
    ind_soc_data_out_ready(fds[1]);
    /* Do stuff for 3 seconds */
    ind_soc_select_and_run(3000);

    INDIGO_ASSERT(socket_called > 0);
    INDIGO_ASSERT(sock_read_seen > 0);
    INDIGO_ASSERT(sock_write_seen > 0);

    return 0;
}
示例#10
0
static void
test_periodic_timer(void)
{
    int count;

    /* Should fire every 'repeat_time_ms' */
    count = 0;
    ind_soc_timer_event_register(timer_callback, &count, 100);
    ind_soc_select_and_run(1000);
    INDIGO_ASSERT(count >= 9 && count <= 11);
    INDIGO_ASSERT(ind_soc_timer_event_unregister(timer_callback, &count) == 0);

    /* A timer may re-register itself with a different period during its callback */
    count = 0;
    ind_soc_timer_event_register(timer_callback_reregister, &count, 100);
    ind_soc_select_and_run(1000);
    INDIGO_ASSERT(count > 50 && count < 100);
    INDIGO_ASSERT(ind_soc_timer_event_unregister(timer_callback_reregister, &count) == 0);

    /* A timer may unregister itself during its callback */
    count = 0;
    ind_soc_timer_event_register(timer_callback_unregister, &count, 100);
    ind_soc_select_and_run(1000);
    INDIGO_ASSERT(count == 1);
    INDIGO_ASSERT(ind_soc_timer_event_unregister(timer_callback_unregister, &count) < 0);
}
示例#11
0
static void
cxn_closing_timeout(void *cookie)
{
    connection_t *cxn;

    cxn = (connection_t *) cookie;

    INDIGO_ASSERT(CONNECTION_STATE(cxn) == INDIGO_CXN_S_CLOSING);

    LOG_WARN(cxn, "Timeout in closing state");

    cxn_state_set(cxn, INDIGO_CXN_S_DISCONNECTED);
}
示例#12
0
static void
cxn_connecting_timeout(void *cookie)
{
    connection_t *cxn;

    cxn = (connection_t *) cookie;

    INDIGO_ASSERT(CONNECTION_STATE(cxn) == INDIGO_CXN_S_CONNECTING);

    LOG_WARN(cxn, "Timeout in connecting state");

    ind_cxn_disconnect(cxn);
}
示例#13
0
void
ft_hash_delete(ft_instance_t ft)
{
    ft_entry_t *entry;
    list_links_t *cur, *next;

    if (ft == NULL) {
        return;
    }
    INDIGO_ASSERT(ft->magic == FT_HASH_MAGIC_NUMBER);

    FT_ITER(ft, entry, cur, next) {
        ft_entry_unlink(ft, entry);
        ft_entry_clear(ft, entry);
    }
示例#14
0
indigo_error_t
ft_hash_flow_add(ft_instance_t ft, indigo_flow_id_t id,
                 of_flow_add_t *flow_add, ft_entry_t **entry_p)
{
    ft_entry_t *entry;
    list_links_t *links;
    indigo_error_t rv;

    INDIGO_ASSERT(ft->magic == FT_HASH_MAGIC_NUMBER);

    LOG_TRACE("Adding flow " INDIGO_FLOW_ID_PRINTF_FORMAT, id);

    if (flow_add->version != OF_VERSION_1_0) { /* @fixme */
        LOG_ERROR("ERROR: bad version in ft_hash_flow_add");
        return INDIGO_ERROR_VERSION;
    }

    /* If flow ID already exists, error. */
    if (ft_id_lookup(ft, id) != NULL) {
        return INDIGO_ERROR_EXISTS;
    }

    /* Grab an entry from the free list */
    if ((links = list_pop(&ft->free_list)) == NULL) {
        ++(ft->status.table_full_errors);
        return INDIGO_ERROR_RESOURCE;
    }
    entry = FT_ENTRY_CONTAINER(links, table);

    if ((rv = ft_entry_setup(entry, id, flow_add)) < 0) {
        return rv;
    }

    ft_entry_link(ft, entry);
    ft->status.adds += 1;
    ft->status.current_count += 1;

    if (entry_p != NULL) {
        *entry_p = entry;
    }

    return INDIGO_ERROR_NONE;
}
示例#15
0
static indigo_time_t
calc_expiration_time(ft_entry_t *entry, int *reason)
{
    indigo_time_t idle_expiration_time = -1, hard_expiration_time = -1;
    INDIGO_ASSERT(entry->hard_timeout || entry->idle_timeout);

    if (entry->hard_timeout > 0) {
        hard_expiration_time = entry->insert_time + entry->hard_timeout*1000;
    }
    if (entry->idle_timeout > 0) {
        idle_expiration_time = entry->last_counter_change + entry->idle_timeout*1000;
    }

    if (hard_expiration_time <= idle_expiration_time) {
        *reason = OF_FLOW_REMOVED_REASON_HARD_TIMEOUT;
        return hard_expiration_time;
    } else {
        *reason = OF_FLOW_REMOVED_REASON_IDLE_TIMEOUT;
        return idle_expiration_time;
    }
}
示例#16
0
/* Test add/remove of sockets */
static void
test_socket_mgmt(void)
{
    int fds[2];
    struct sock_counters counters[2];

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
        perror("socketpair");
        abort();
    }

    /* Unregistering a not-registered socket should fail */
    INDIGO_ASSERT(ind_soc_socket_unregister(fds[0]) < 0);

    /* Adding and then unregistering a socket should succeed */
    INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, &counters[0]) == 0);
    INDIGO_ASSERT(ind_soc_socket_unregister(fds[0]) == 0);

    /* Trying to unregister twice should fail */
    INDIGO_ASSERT(ind_soc_socket_unregister(fds[0]) < 0);

    /* Trying to register twice should fail */
    INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, &counters[0]) == 0);
    INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, &counters[0]) < 0);

    /* Add another socket, then remove the first */
    INDIGO_ASSERT(ind_soc_socket_register(fds[1], socket_callback, &counters[1]) == 0);
    INDIGO_ASSERT(ind_soc_socket_unregister(fds[0]) == 0);

    /* Write one byte to fds[1] */
    ind_soc_data_out_ready(fds[1]);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 1);

    /* Expect no events from the not-registered fds[0] */
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Register fds[0] and expect a read event */
    INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, &counters[0]) == 0);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 1);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);

    INDIGO_ASSERT(ind_soc_socket_unregister(fds[0]) == 0);
    INDIGO_ASSERT(ind_soc_socket_unregister(fds[1]) == 0);

    close(fds[0]);
    close(fds[1]);
}
示例#17
0
static void
test_socket(void)
{
    int fds[2];
    struct sock_counters counters[2];
    indigo_time_t start_time, end_time;
    struct itimerval itv;

    signal(SIGALRM, sigalrm);

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
        perror("socketpair");
        abort();
    }

    INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, &counters[0]) == 0);
    INDIGO_ASSERT(ind_soc_socket_register(fds[1], socket_callback, &counters[1]) == 0);

    /* No events ready */
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Write one byte to fds[0] */
    ind_soc_data_out_ready(fds[0]);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 1);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Read one byte from fds[1] */
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 1);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Write one byte to each of fds[0] and fds[1] */
    ind_soc_data_out_ready(fds[0]);
    ind_soc_data_out_ready(fds[1]);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 1);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 1);

    /* Read one byte from each of fds[0] and fds[1] */
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 1);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 1);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Write one byte to fds[0] */
    ind_soc_data_out_ready(fds[0]);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 1);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Pause data in from fds[1], expect no reads */
    ind_soc_data_in_pause(fds[1]);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Resume data in from fds[1] */
    ind_soc_data_in_resume(fds[1]);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 1);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Block for some time with no events */
    memset(counters, 0, sizeof(counters));
    start_time = INDIGO_CURRENT_TIME;
    ind_soc_select_and_run(100);
    end_time = INDIGO_CURRENT_TIME;
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);
    INDIGO_ASSERT((end_time - start_time) >= 100 &&
                  (end_time - start_time) < 200);

    /* Block for some time until SIGALRM, which causes read ready on fd[1] */
    memset(counters, 0, sizeof(counters));
    memset(&itv, 0, sizeof(itv));
    sigalrm_write_fd = fds[0];
    itv.it_value.tv_usec = 100*1000;
    setitimer(ITIMER_REAL, &itv, NULL);
    ind_soc_select_and_run(200);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 1);
    INDIGO_ASSERT(counters[1].write == 0);

    INDIGO_ASSERT(ind_soc_socket_unregister(fds[0]) == 0);
    INDIGO_ASSERT(ind_soc_socket_unregister(fds[1]) == 0);

    close(fds[0]);
    close(fds[1]);
}
示例#18
0
static void
test_task(void)
{
    int counters[2];
    int i;

    task_counter_limit = 3;

    INDIGO_ASSERT(ind_soc_task_register(task_callback, &counters[0], 0) == INDIGO_ERROR_NONE);

    /* Task should immediately run */
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0] == 1);

    /* Task should keep running */
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0] == 1);

    INDIGO_ASSERT(ind_soc_task_register(task_callback, &counters[1], 0) == INDIGO_ERROR_NONE);

    /* Both tasks should run until the counter == 3 */
    memset(counters, 0, sizeof(counters));
    for (i = 1; i <= 3; i++) {
        ind_soc_select_and_run(0);
        INDIGO_ASSERT(counters[0] == i);
        INDIGO_ASSERT(counters[1] == i);
    }

    /* No tasks should run after finishing */
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0] == 0);
    INDIGO_ASSERT(counters[1] == 0);

    /* Task should yield after 10 ms */
    INDIGO_ASSERT(ind_soc_task_register(task_callback_yield, &counters[0], 0) == INDIGO_ERROR_NONE);
    memset(counters, 0, sizeof(counters));
    i = 0;
    while (counters[0] < 100) {
        int tmp;
        tmp = counters[0];
        ind_soc_select_and_run(0);
        tmp = counters[0] - tmp;
        INDIGO_ASSERT(tmp <= 10); /* 10 ms/timeslice / 1+ ms/unit <= 10 units/timeslice */
        i++;
    }
    INDIGO_ASSERT(i >= 10); /* (100 units * 1+ ms/unit) / 10 ms/timeslice >= 10 timeslices */
    INDIGO_ASSERT(100 / i >= 5); /* average at least 5 units per timeslice */

    /* Excessively long callback should trigger a warning (not checked) */
    INDIGO_ASSERT(ind_soc_task_register(task_callback_long, &counters[0], 0) == INDIGO_ERROR_NONE);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0] == 1);

    /* Task should be repeatedly rescheduled in the same call to ind_soc_select_and_run */
    INDIGO_ASSERT(ind_soc_task_register(task_callback_yield, &counters[0], 0) == INDIGO_ERROR_NONE);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(500);
    INDIGO_ASSERT(counters[0] == 100);
}
示例#19
0
static void
test_priority(void)
{
    int read_fds[3], write_fds[3];
    struct sock_counters counters[3];
    int timer_counters[3];
    int task_counters[3];
    int i;

    task_counter_limit = 1;

    for (i = 0; i < 3; i++) {
        int fds[2];
        if (pipe(fds) < 0) {
            perror("pipe");
            abort();
        }
        read_fds[i] = fds[0];
        write_fds[i] = fds[1];
    }

    /* High priority */
    INDIGO_ASSERT(ind_soc_socket_register_with_priority(
                      read_fds[0], socket_callback, &counters[0], IND_SOC_HIGH_PRIORITY) == 0);

    INDIGO_ASSERT(ind_soc_timer_event_register_with_priority(
                      timer_callback, &timer_counters[0], IND_SOC_TIMER_IMMEDIATE, IND_SOC_HIGH_PRIORITY) == 0);

    INDIGO_ASSERT(ind_soc_task_register(
                      task_callback, &task_counters[0], IND_SOC_HIGH_PRIORITY) == 0);

    /* Medium priority */
    INDIGO_ASSERT(ind_soc_socket_register_with_priority(
                      read_fds[1], socket_callback, &counters[1], IND_SOC_NORMAL_PRIORITY) == 0);

    INDIGO_ASSERT(ind_soc_timer_event_register_with_priority(
                      timer_callback, &timer_counters[1], IND_SOC_TIMER_IMMEDIATE, IND_SOC_NORMAL_PRIORITY) == 0);

    INDIGO_ASSERT(ind_soc_task_register(
                      task_callback, &task_counters[1], IND_SOC_NORMAL_PRIORITY) == 0);

    /* Low priority */
    INDIGO_ASSERT(ind_soc_socket_register_with_priority(
                      read_fds[2], socket_callback, &counters[2], IND_SOC_LOW_PRIORITY) == 0);

    INDIGO_ASSERT(ind_soc_timer_event_register_with_priority(
                      timer_callback, &timer_counters[2], IND_SOC_TIMER_IMMEDIATE, IND_SOC_LOW_PRIORITY) == 0);

    INDIGO_ASSERT(ind_soc_task_register(
                      task_callback, &task_counters[2], IND_SOC_LOW_PRIORITY) == 0);

    /* Make all sockets ready */
    for (i = 0; i < 3; i++) {
        write(write_fds[i], "x", 1);
    }

    /* Higher priority events should run first */
    memset(counters, 0, sizeof(counters));
    memset(timer_counters, 0, sizeof(timer_counters));
    memset(task_counters, 0, sizeof(task_counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 1);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[2].read == 0);
    INDIGO_ASSERT(timer_counters[0] == 1);
    INDIGO_ASSERT(timer_counters[1] == 0);
    INDIGO_ASSERT(timer_counters[2] == 0);
    INDIGO_ASSERT(task_counters[0] == 1);
    INDIGO_ASSERT(task_counters[1] == 0);
    INDIGO_ASSERT(task_counters[2] == 0);

    /* Medium priority events should run next */
    memset(counters, 0, sizeof(counters));
    memset(timer_counters, 0, sizeof(timer_counters));
    memset(task_counters, 0, sizeof(task_counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[1].read == 1);
    INDIGO_ASSERT(counters[2].read == 0);
    INDIGO_ASSERT(timer_counters[0] == 0);
    INDIGO_ASSERT(timer_counters[1] == 1);
    INDIGO_ASSERT(timer_counters[2] == 0);
    INDIGO_ASSERT(task_counters[0] == 0);
    INDIGO_ASSERT(task_counters[1] == 1);
    INDIGO_ASSERT(task_counters[2] == 0);

    /* New high priority events should run next */
    write(write_fds[0], "x", 1);
    INDIGO_ASSERT(ind_soc_task_register(
                      task_callback, &task_counters[0], IND_SOC_HIGH_PRIORITY) == 0);
    memset(counters, 0, sizeof(counters));
    memset(timer_counters, 0, sizeof(timer_counters));
    memset(task_counters, 0, sizeof(task_counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 1);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[2].read == 0);
    INDIGO_ASSERT(timer_counters[0] == 0);
    INDIGO_ASSERT(timer_counters[1] == 0);
    INDIGO_ASSERT(timer_counters[2] == 0);
    INDIGO_ASSERT(task_counters[0] == 1);
    INDIGO_ASSERT(task_counters[1] == 0);
    INDIGO_ASSERT(task_counters[2] == 0);

    /* Low priority events should run last */
    memset(counters, 0, sizeof(counters));
    memset(timer_counters, 0, sizeof(timer_counters));
    memset(task_counters, 0, sizeof(task_counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[2].read == 1);
    INDIGO_ASSERT(timer_counters[0] == 0);
    INDIGO_ASSERT(timer_counters[1] == 0);
    INDIGO_ASSERT(timer_counters[2] == 1);
    INDIGO_ASSERT(task_counters[0] == 0);
    INDIGO_ASSERT(task_counters[1] == 0);
    INDIGO_ASSERT(task_counters[2] == 1);

    INDIGO_ASSERT(ind_soc_socket_unregister(read_fds[0]) == 0);
    INDIGO_ASSERT(ind_soc_socket_unregister(read_fds[1]) == 0);
    INDIGO_ASSERT(ind_soc_socket_unregister(read_fds[2]) == 0);

    /* One-shot timers, already unregistered */
    INDIGO_ASSERT(ind_soc_timer_event_unregister(
                      timer_callback, &timer_counters[0]) < 0);
    INDIGO_ASSERT(ind_soc_timer_event_unregister(
                      timer_callback, &timer_counters[1]) < 0);
    INDIGO_ASSERT(ind_soc_timer_event_unregister(
                      timer_callback, &timer_counters[3]) < 0);

    for (i = 0; i < 3; i++) {
        close(read_fds[i]);
        close(write_fds[i]);
    }
}