aboutsummaryrefslogtreecommitdiffstats
path: root/python/gevent/libuv/_corecffi_source.c
blob: 83fe82ee94421aeae433272d944df7df858d9734 (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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include <string.h>
#include "uv.h"

typedef void* GeventWatcherObject;

static int python_callback(GeventWatcherObject handle, int revents);
static void python_queue_callback(uv_handle_t* watcher_ptr, int revents);
static void python_handle_error(GeventWatcherObject handle, int revents);
static void python_stop(GeventWatcherObject handle);

static void _gevent_noop(void* handle) {}

static void (*gevent_noop)(void* handle) = &_gevent_noop;

static void _gevent_generic_callback1_unused(uv_handle_t* watcher, int arg)
{
    // Python code may set this to NULL or even change it
    // out from under us, which would tend to break things.
    GeventWatcherObject handle = watcher->data;
    const int cb_result = python_callback(handle, arg);
    switch(cb_result) {
        case -1:
            // in case of exception, call self.loop.handle_error;
            // this function is also responsible for stopping the watcher
            // and allowing memory to be freed
            python_handle_error(handle, arg);
        break;
        case 1:
            // Code to stop the event IF NEEDED. Note that if python_callback
            // has disposed of the last reference to the handle,
            // `watcher` could now be invalid/disposed memory!
            if (!uv_is_active(watcher)) {
                if (watcher->data != handle) {
                    if (watcher->data) {
                        // If Python set the data to NULL, then they
                        // expected to be stopped. That's fine.
                        // Otherwise, something weird happened.
                        fprintf(stderr,
                                "WARNING: gevent: watcher handle changed in callback "
                                "from %p to %p for watcher at %p of type %d\n",
                                handle, watcher->data, watcher, watcher->type);
                        // There's a very good chance that the object the
                        // handle referred to has been changed and/or the
                        // old handle has been deallocated (most common), so
                        // passing the old handle will crash. Instead we
                        // pass a sigil to let python distinguish this case.
                        python_stop(NULL);
                    }
                }
                else {
                    python_stop(handle);
                }
            }
        break;
        case 2:
            // watcher is already stopped and dead, nothing to do.
        break;
        default:
            fprintf(stderr,
                    "WARNING: gevent: Unexpected return value %d from Python callback "
                    "for watcher %p (of type %d) and handle %p\n",
                    cb_result,
                    watcher, watcher->type, handle);
            // XXX: Possible leaking of resources here? Should we be
            // closing the watcher?
    }
}


static void _gevent_generic_callback1(uv_handle_t* watcher, int arg)
{
	python_queue_callback(watcher, arg);
}

static void _gevent_generic_callback0(uv_handle_t* handle)
{
    _gevent_generic_callback1(handle, 0);
}

static void _gevent_async_callback0(uv_async_t* handle)
{
    _gevent_generic_callback0((uv_handle_t*)handle);
}

static void _gevent_timer_callback0(uv_timer_t* handle)
{
    _gevent_generic_callback0((uv_handle_t*)handle);
}

static void _gevent_prepare_callback0(uv_prepare_t* handle)
{
    _gevent_generic_callback0((uv_handle_t*)handle);
}

static void _gevent_check_callback0(uv_check_t* handle)
{
    _gevent_generic_callback0((uv_handle_t*)handle);
}

static void _gevent_idle_callback0(uv_idle_t* handle)
{
    _gevent_generic_callback0((uv_handle_t*)handle);
}

static void _gevent_signal_callback1(uv_signal_t* handle, int signum)
{
    _gevent_generic_callback1((uv_handle_t*)handle, signum);
}


static void _gevent_poll_callback2(void* handle, int status, int events)
{
    _gevent_generic_callback1(handle, status < 0 ? status : events);
}

static void _gevent_fs_event_callback3(void* handle, const char* filename, int events, int status)
{
    _gevent_generic_callback1(handle, status < 0 ? status : events);
}


typedef struct _gevent_fs_poll_s {
    uv_fs_poll_t handle;
    uv_stat_t curr;
    uv_stat_t prev;
} gevent_fs_poll_t;

static void _gevent_fs_poll_callback3(void* handlep, int status, const uv_stat_t* prev, const uv_stat_t* curr)
{
    // stat pointers are valid for this callback only.
    // if given, copy them into our structure, where they can be reached
    // from python, just like libev's watcher does, before calling
    // the callback.

    // The callback is invoked with status < 0 if path does not exist
    // or is inaccessible. The watcher is not stopped but your
    // callback is not called again until something changes (e.g. when
    // the file is created or the error reason changes).
    // In that case the fields will be 0 in curr/prev.


    gevent_fs_poll_t* handle = (gevent_fs_poll_t*)handlep;
    assert(status == 0);

    handle->curr = *curr;
    handle->prev = *prev;

    _gevent_generic_callback1((uv_handle_t*)handle, 0);
}

static void gevent_uv_walk_callback_close(uv_handle_t* handle, void* arg)
{
	if( handle && !uv_is_closing(handle) ) {
		uv_close(handle, NULL);
	}
}

static void gevent_close_all_handles(uv_loop_t* loop)
{
	uv_walk(loop, gevent_uv_walk_callback_close, NULL);
}

static void gevent_zero_timer(uv_timer_t* handle)
{
	memset(handle, 0, sizeof(uv_timer_t));
}

static void gevent_zero_check(uv_check_t* handle)
{
	memset(handle, 0, sizeof(uv_check_t));
}

static void gevent_zero_prepare(uv_prepare_t* handle)
{
	memset(handle, 0, sizeof(uv_prepare_t));
}

static void gevent_zero_loop(uv_loop_t* handle)
{
	memset(handle, 0, sizeof(uv_loop_t));
}