summaryrefslogtreecommitdiff
path: root/src/mbgl/util/uv-messenger.c
blob: 935b6f1c41f4473a9dbd025f6aa433f379758fe9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <mbgl/util/uv-messenger.h>
#include <mbgl/util/queue.h>

#include <stdlib.h>
#include <assert.h>

typedef struct {
    void *data;
    void *queue[2];
} uv__messenger_item_t;

#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
void uv__messenger_callback(uv_async_t *async, int status) {
#pragma clang diagnostic pop
#else
void uv__messenger_callback(uv_async_t *async) {
#endif
    uv_messenger_t *msgr = (uv_messenger_t *)async->data;

    uv__messenger_item_t *item;
    QUEUE *head;

    while (1) {
        uv_mutex_lock(&msgr->mutex);
        if (QUEUE_EMPTY(&msgr->queue)) {
            uv_mutex_unlock(&msgr->mutex);
            break;
        }

        head = QUEUE_HEAD(&msgr->queue);
        item = QUEUE_DATA(head, uv__messenger_item_t, queue);
        QUEUE_REMOVE(head);
        uv_mutex_unlock(&msgr->mutex);

        msgr->callback(item->data);

        free(item);
    }
}

int uv_messenger_init(uv_loop_t *loop, uv_messenger_t *msgr, uv_messenger_cb callback) {
    int ret = uv_mutex_init(&msgr->mutex);
    if (ret < 0) {
        return ret;
    }

    msgr->callback = callback;
    msgr->stop_callback = NULL;

    QUEUE_INIT(&msgr->queue);

    msgr->async.data = msgr;
    return uv_async_init(loop, &msgr->async, uv__messenger_callback);
}

void uv_messenger_send(uv_messenger_t *msgr, void *data) {
    uv__messenger_item_t *item = (uv__messenger_item_t *)malloc(sizeof(uv__messenger_item_t));
    item->data = data;

    uv_mutex_lock(&msgr->mutex);
    QUEUE_INSERT_TAIL(&msgr->queue, &item->queue);
    uv_mutex_unlock(&msgr->mutex);

    uv_async_send(&msgr->async);
}

void uv_messenger_ref(uv_messenger_t *msgr) {
    uv_ref((uv_handle_t *)&msgr->async);
}

void uv_messenger_unref(uv_messenger_t *msgr) {
    uv_unref((uv_handle_t *)&msgr->async);
}

void uv__messenger_stop_callback(uv_handle_t *handle) {
    uv_messenger_t *msgr = (uv_messenger_t *)handle->data;
    msgr->stop_callback(msgr);
}

void uv_messenger_stop(uv_messenger_t *msgr, uv_messenger_stop_cb stop_callback) {
    assert(!msgr->stop_callback);
    msgr->stop_callback = stop_callback;
    uv_close((uv_handle_t *)&msgr->async, uv__messenger_stop_callback);
}