Hello,

I hope this message finds you well.

The following issue is likely self-inflicted but it is not clear how at
this point.

The attached test code is a program that runs with two threads (the main
thread and a child pthread).

The main thread:
1. Initializes the child event watchers (one async, one timer)
2. Calls pthread_create() which results in the ev_run() executing in the
child thread
3. calls ev_timer_start() with a value of 0.5 seconds
4. sleeps for several seconds, to ensure that the child thread will get
called

Note: I typically use pthread conditionals to ensure that an event on
another thread gets executed.

The child thread:
1. After the ev_timer_start() is called it *should* wake up 0.5 seconds
later, printing out a message showing that the callback has occurred

What I see happening, instead of waking up 0.5 seconds later, is it takes
roughly 60 seconds for the timer to start going off. I put some debug in
the ev.c code and determined that within the ev_run() function, the
waittime getting passed to backend_poll was 59.793 seconds.

It appears as though ev_timer_start() does not cause the backend_poll to
wake up. Is this the expected behavior or am I doing something wrong?

I have also attached the config.log file so you can see the architecture
where I am having problems. Note that I also tried the same program on a
x64 system with the same results.

Thanks very much for your time.

Regards,

Chris Zahka

Attachment: config.log
Description: Binary data

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <ev.h>
#include <unistd.h>
#include <pthread.h>


static ev_async m_HaltChildWatcher;
static ev_timer m_PeriodicTimerWatcher;
static struct ev_loop *m_ChildLoop;

static void* DoChildProcessingInThread(void* args)
{
    ev_run(m_ChildLoop, 0);
    pthread_exit(NULL);
    return NULL;
}

static void PeriodicTimerCallback(struct ev_loop *loop, ev_timer *watcher,
        int revents)
{
    printf("PeriodicTimerCallback()\n");
}

static void HaltChildCallback(struct ev_loop *loop, ev_async *watcher,
        int revents)
{
    ev_async_stop(loop, watcher);

    ev_timer_stop(loop, &m_PeriodicTimerWatcher);

    ev_break(loop, EVBREAK_ALL);
}

static int InitializeChild(const float timeout)
{

    m_ChildLoop = ev_loop_new(0);

    ev_async_init(&m_HaltChildWatcher, HaltChildCallback);

    ev_async_start(m_ChildLoop, &m_HaltChildWatcher);

    ev_timer_init(&m_PeriodicTimerWatcher, PeriodicTimerCallback, timeout,
            timeout);

    return 0;
}

static void StartTimer()
{
    if (!ev_is_active(&m_PeriodicTimerWatcher)) {
        ev_timer_start(m_ChildLoop,
                &m_PeriodicTimerWatcher);
    }
}

static int StartChild(pthread_t *thread, const pthread_attr_t *attr)
{
    const int status = pthread_create(thread, attr, DoChildProcessingInThread,
    NULL);

    if (0 != status) {
        printf("Thread failed to create. errno = %s\n", strerror(status));
        return -1;
    }

    return 0;
}

static void StopChild()
{
    if (!(ev_async_pending(&m_HaltChildWatcher))) {
        ev_async_send(m_ChildLoop, &m_HaltChildWatcher);
    }
}

static void CleanupChild()
{
    ev_loop_destroy(m_ChildLoop);
}

int main(int argc, char **argv)
{
    if (argc != 2) {
        printf("must specify a 0 or 1\n");
        return -1;
    }

    const int beforeOrAfter = atoi(argv[1]);

    if (0 == beforeOrAfter) {
        printf("Starting timer before event loop starts running\n");
    } else if (1 == beforeOrAfter) {
        printf("Starting timer after event loop starts running\n");
    } else {
        printf("invalid argument\n");
        return -1;
    }

    pthread_t thread;
    pthread_attr_t attr;

    pthread_attr_init(&attr);

    int result = InitializeChild(0.5);

    if (0 != result) {
        printf("InitializeChild() failed. exiting\n");
        return -1;
    }

    if (0 == beforeOrAfter) {
        StartTimer();
    }

    result = StartChild(&thread, &attr);

    if (0 != result) {
        printf("StartChild() failed. exiting\n");
        return -1;
    }

    sleep(1);  // attempting to ensure that ev_run() has started in the child
               // thread before proceeding

    if (1 == beforeOrAfter) {
        StartTimer();
    }

    sleep(65); // currently sleeping for 65 seconds since the default time
               // epoll_poll() will sleep is MAX_BLOCKTIME (~60 seconds)

    StopChild();

    result = pthread_join(thread, NULL);

    if (0 != result) {
        printf("pthread_join() failed. exiting\n");
        return -1;
    }

    CleanupChild();

    return (1);
}

Attachment: Makefile
Description: Binary data

_______________________________________________
libev mailing list
[email protected]
http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev

Reply via email to