iodine 0.4.19 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/CHANGELOG.md +22 -0
- data/LIMITS.md +19 -9
- data/README.md +92 -77
- data/SPEC-PubSub-Draft.md +113 -0
- data/SPEC-Websocket-Draft.md +127 -143
- data/bin/http-hello +0 -1
- data/bin/raw-rbhttp +1 -1
- data/bin/raw_broadcast +8 -10
- data/bin/updated api +2 -2
- data/bin/ws-broadcast +2 -4
- data/bin/ws-echo +2 -2
- data/examples/config.ru +13 -13
- data/examples/echo.ru +5 -6
- data/examples/hello.ru +2 -3
- data/examples/info.md +316 -0
- data/examples/pubsub_engine.ru +81 -0
- data/examples/redis.ru +9 -9
- data/examples/shootout.ru +45 -11
- data/ext/iodine/defer.c +194 -297
- data/ext/iodine/defer.h +61 -53
- data/ext/iodine/evio.c +0 -260
- data/ext/iodine/evio.h +50 -22
- data/ext/iodine/evio_callbacks.c +26 -0
- data/ext/iodine/evio_epoll.c +251 -0
- data/ext/iodine/evio_kqueue.c +193 -0
- data/ext/iodine/extconf.rb +1 -1
- data/ext/iodine/facil.c +1420 -542
- data/ext/iodine/facil.h +151 -64
- data/ext/iodine/fio_ary.h +418 -0
- data/ext/iodine/{base64.c → fio_base64.c} +33 -24
- data/ext/iodine/{base64.h → fio_base64.h} +6 -7
- data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
- data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
- data/ext/iodine/fio_hashmap.h +759 -0
- data/ext/iodine/fio_json_parser.h +651 -0
- data/ext/iodine/fio_llist.h +257 -0
- data/ext/iodine/fio_mem.c +672 -0
- data/ext/iodine/fio_mem.h +140 -0
- data/ext/iodine/fio_random.c +248 -0
- data/ext/iodine/{random.h → fio_random.h} +11 -14
- data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
- data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
- data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
- data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
- data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
- data/ext/iodine/fio_siphash.h +18 -0
- data/ext/iodine/fio_tmpfile.h +38 -0
- data/ext/iodine/fiobj.h +24 -7
- data/ext/iodine/fiobj4sock.h +23 -0
- data/ext/iodine/fiobj_ary.c +143 -226
- data/ext/iodine/fiobj_ary.h +17 -16
- data/ext/iodine/fiobj_data.c +1160 -0
- data/ext/iodine/fiobj_data.h +164 -0
- data/ext/iodine/fiobj_hash.c +298 -406
- data/ext/iodine/fiobj_hash.h +101 -54
- data/ext/iodine/fiobj_json.c +478 -601
- data/ext/iodine/fiobj_json.h +34 -9
- data/ext/iodine/fiobj_numbers.c +383 -51
- data/ext/iodine/fiobj_numbers.h +87 -11
- data/ext/iodine/fiobj_str.c +423 -184
- data/ext/iodine/fiobj_str.h +81 -32
- data/ext/iodine/fiobject.c +273 -522
- data/ext/iodine/fiobject.h +477 -112
- data/ext/iodine/http.c +2243 -83
- data/ext/iodine/http.h +842 -121
- data/ext/iodine/http1.c +810 -385
- data/ext/iodine/http1.h +16 -39
- data/ext/iodine/http1_parser.c +146 -74
- data/ext/iodine/http1_parser.h +15 -4
- data/ext/iodine/http_internal.c +1258 -0
- data/ext/iodine/http_internal.h +226 -0
- data/ext/iodine/http_mime_parser.h +341 -0
- data/ext/iodine/iodine.c +86 -68
- data/ext/iodine/iodine.h +26 -11
- data/ext/iodine/iodine_helpers.c +8 -7
- data/ext/iodine/iodine_http.c +487 -324
- data/ext/iodine/iodine_json.c +304 -0
- data/ext/iodine/iodine_json.h +6 -0
- data/ext/iodine/iodine_protocol.c +107 -45
- data/ext/iodine/iodine_pubsub.c +526 -225
- data/ext/iodine/iodine_pubsub.h +10 -0
- data/ext/iodine/iodine_websockets.c +268 -510
- data/ext/iodine/iodine_websockets.h +2 -4
- data/ext/iodine/pubsub.c +726 -432
- data/ext/iodine/pubsub.h +85 -103
- data/ext/iodine/rb-call.c +4 -4
- data/ext/iodine/rb-defer.c +46 -22
- data/ext/iodine/rb-fiobj2rb.h +117 -0
- data/ext/iodine/rb-rack-io.c +73 -238
- data/ext/iodine/rb-rack-io.h +2 -2
- data/ext/iodine/rb-registry.c +35 -93
- data/ext/iodine/rb-registry.h +1 -0
- data/ext/iodine/redis_engine.c +742 -304
- data/ext/iodine/redis_engine.h +42 -39
- data/ext/iodine/resp_parser.h +311 -0
- data/ext/iodine/sock.c +627 -490
- data/ext/iodine/sock.h +345 -297
- data/ext/iodine/spnlock.inc +15 -4
- data/ext/iodine/websocket_parser.h +16 -20
- data/ext/iodine/websockets.c +188 -257
- data/ext/iodine/websockets.h +24 -133
- data/lib/iodine.rb +52 -7
- data/lib/iodine/cli.rb +6 -24
- data/lib/iodine/json.rb +40 -0
- data/lib/iodine/version.rb +1 -1
- data/lib/iodine/websocket.rb +5 -3
- data/lib/rack/handler/iodine.rb +58 -13
- metadata +38 -48
- data/bin/ws-shootout +0 -107
- data/examples/broadcast.ru +0 -56
- data/ext/iodine/bscrypt-common.h +0 -116
- data/ext/iodine/bscrypt.h +0 -49
- data/ext/iodine/fio2resp.c +0 -60
- data/ext/iodine/fio2resp.h +0 -51
- data/ext/iodine/fio_dict.c +0 -446
- data/ext/iodine/fio_dict.h +0 -99
- data/ext/iodine/fio_hash_table.h +0 -370
- data/ext/iodine/fio_list.h +0 -111
- data/ext/iodine/fiobj_internal.h +0 -280
- data/ext/iodine/fiobj_primitives.c +0 -131
- data/ext/iodine/fiobj_primitives.h +0 -55
- data/ext/iodine/fiobj_sym.c +0 -135
- data/ext/iodine/fiobj_sym.h +0 -60
- data/ext/iodine/hex.c +0 -124
- data/ext/iodine/hex.h +0 -70
- data/ext/iodine/http1_request.c +0 -81
- data/ext/iodine/http1_request.h +0 -58
- data/ext/iodine/http1_response.c +0 -417
- data/ext/iodine/http1_response.h +0 -95
- data/ext/iodine/http_request.c +0 -111
- data/ext/iodine/http_request.h +0 -102
- data/ext/iodine/http_response.c +0 -1703
- data/ext/iodine/http_response.h +0 -250
- data/ext/iodine/misc.c +0 -182
- data/ext/iodine/misc.h +0 -74
- data/ext/iodine/random.c +0 -208
- data/ext/iodine/redis_connection.c +0 -278
- data/ext/iodine/redis_connection.h +0 -86
- data/ext/iodine/resp.c +0 -842
- data/ext/iodine/resp.h +0 -261
- data/ext/iodine/siphash.c +0 -154
- data/ext/iodine/siphash.h +0 -22
- data/ext/iodine/xor-crypt.c +0 -193
- data/ext/iodine/xor-crypt.h +0 -107
data/ext/iodine/defer.h
CHANGED
|
@@ -23,7 +23,7 @@ call `defer_clear_queue` before exiting the program.
|
|
|
23
23
|
#define LIB_DEFER_VERSION_MINOR 1
|
|
24
24
|
#define LIB_DEFER_VERSION_PATCH 2
|
|
25
25
|
|
|
26
|
-
/* child process reaping is enabled
|
|
26
|
+
/* child process reaping is can be enabled as a default */
|
|
27
27
|
#ifndef NO_CHILD_REAPER
|
|
28
28
|
#define NO_CHILD_REAPER 0
|
|
29
29
|
#endif
|
|
@@ -54,79 +54,87 @@ Thread Pool support
|
|
|
54
54
|
/** an opaque thread pool type */
|
|
55
55
|
typedef struct defer_pool *pool_pt;
|
|
56
56
|
|
|
57
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Starts a thread pool that will run deferred tasks in the background.
|
|
59
|
+
*
|
|
60
|
+
* The `defer_idle` callback will be used to handle waiting threads. It can be
|
|
61
|
+
* used to sleep, or run background tasks. It will run concurrently and
|
|
62
|
+
* continuesly for all the threads in the pool that are idling.
|
|
63
|
+
*
|
|
64
|
+
* If `defer_idle` is NULL, a fallback to `nanosleep` will be used.
|
|
65
|
+
*/
|
|
58
66
|
pool_pt defer_pool_start(unsigned int thread_count);
|
|
67
|
+
|
|
59
68
|
/** Signals a running thread pool to stop. Returns immediately. */
|
|
60
69
|
void defer_pool_stop(pool_pt pool);
|
|
61
|
-
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Waits for a running thread pool, joining threads and finishing all tasks.
|
|
73
|
+
*
|
|
74
|
+
* This function MUST be called in order to free the pool's data (the
|
|
75
|
+
* `pool_pt`).
|
|
76
|
+
*/
|
|
62
77
|
void defer_pool_wait(pool_pt pool);
|
|
78
|
+
|
|
63
79
|
/** Returns TRUE (1) if the pool is hadn't been signaled to finish up. */
|
|
64
80
|
int defer_pool_is_active(pool_pt pool);
|
|
65
81
|
|
|
66
82
|
/**
|
|
67
|
-
OVERRIDE THIS to replace the default pthread implementation.
|
|
68
|
-
|
|
69
|
-
Accepts a pointer to a function and a single argument that should be executed
|
|
70
|
-
within a new thread.
|
|
71
|
-
|
|
72
|
-
The function should allocate memory for the thread object and return a
|
|
73
|
-
to the allocated memory that identifies the thread.
|
|
74
|
-
|
|
75
|
-
On error NULL should be returned.
|
|
76
|
-
*/
|
|
77
|
-
void *defer_new_thread(void *(*thread_func)(void *),
|
|
83
|
+
* OVERRIDE THIS to replace the default pthread implementation.
|
|
84
|
+
*
|
|
85
|
+
* Accepts a pointer to a function and a single argument that should be executed
|
|
86
|
+
* within a new thread.
|
|
87
|
+
*
|
|
88
|
+
* The function should allocate memory for the thread object and return a
|
|
89
|
+
* pointer to the allocated memory that identifies the thread.
|
|
90
|
+
*
|
|
91
|
+
* On error NULL should be returned.
|
|
92
|
+
*/
|
|
93
|
+
void *defer_new_thread(void *(*thread_func)(void *), void *arg);
|
|
78
94
|
|
|
79
95
|
/**
|
|
80
|
-
OVERRIDE THIS to replace the default pthread implementation.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
96
|
+
* OVERRIDE THIS to replace the default pthread implementation.
|
|
97
|
+
*
|
|
98
|
+
* Frees the memory asociated with a thread indentifier (allows the thread to
|
|
99
|
+
* run it's course, just the identifier is freed).
|
|
100
|
+
*/
|
|
101
|
+
void defer_free_thread(void *p_thr);
|
|
84
102
|
|
|
85
|
-
|
|
86
|
-
|
|
103
|
+
/**
|
|
104
|
+
* OVERRIDE THIS to replace the default pthread implementation.
|
|
105
|
+
*
|
|
106
|
+
* Accepts a pointer returned from `defer_new_thread` (should also free any
|
|
107
|
+
* allocated memory) and joins the associated thread.
|
|
108
|
+
*
|
|
109
|
+
* Return value is ignored.
|
|
110
|
+
*/
|
|
87
111
|
int defer_join_thread(void *p_thr);
|
|
88
112
|
|
|
89
113
|
/**
|
|
90
|
-
OVERRIDE THIS to replace the default pthread implementation.
|
|
91
|
-
|
|
92
|
-
Throttles or reschedules the current running thread. Default implementation
|
|
93
|
-
simply micro-sleeps.
|
|
94
|
-
*/
|
|
114
|
+
* OVERRIDE THIS to replace the default pthread implementation.
|
|
115
|
+
*
|
|
116
|
+
* Throttles or reschedules the current running thread. Default implementation
|
|
117
|
+
* simply micro-sleeps.
|
|
118
|
+
*/
|
|
95
119
|
void defer_thread_throttle(unsigned long microsec);
|
|
96
120
|
|
|
97
|
-
/* *****************************************************************************
|
|
98
|
-
Child Process support (`fork`)
|
|
99
|
-
***************************************************************************** */
|
|
100
|
-
|
|
101
121
|
/**
|
|
102
|
-
OVERRIDE THIS to replace the default
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
int defer_new_child(void);
|
|
122
|
+
* OVERRIDE THIS to replace the default nanosleep implementation.
|
|
123
|
+
*
|
|
124
|
+
* A thread entering this function should wait for new evennts.
|
|
125
|
+
*/
|
|
126
|
+
void defer_thread_wait(pool_pt pool, void *p_thr);
|
|
108
127
|
|
|
109
128
|
/**
|
|
110
|
-
*
|
|
111
|
-
* All existing tasks will run in all processes (multiple times).
|
|
112
|
-
*
|
|
113
|
-
* It's possible to synchronize workload across processes by using a pipe (or
|
|
114
|
-
* pipes) and a self-scheduling event that reads instructions from the pipe.
|
|
129
|
+
* OVERRIDE THIS to replace the default implementation (which does nothing).
|
|
115
130
|
*
|
|
116
|
-
* This
|
|
117
|
-
*
|
|
118
|
-
* remain active for the application's lifetime).
|
|
119
|
-
*
|
|
120
|
-
* Returns 0 on success, -1 on error and a positive number if this is a child
|
|
121
|
-
* process that was forked.
|
|
131
|
+
* This should signal a single waiting thread to wake up (a new task entered the
|
|
132
|
+
* queue).
|
|
122
133
|
*/
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
|
|
127
|
-
int defer_fork_is_active(void);
|
|
128
|
-
/** Returns the process number for the current working proceess. 0 == parent. */
|
|
129
|
-
int defer_fork_pid(void);
|
|
134
|
+
void defer_thread_signal(void);
|
|
135
|
+
|
|
136
|
+
/** Call this function after forking, to make sure no locks are engaged. */
|
|
137
|
+
void defer_on_fork(void);
|
|
130
138
|
|
|
131
139
|
#ifdef DEBUG
|
|
132
140
|
/** minor testing facilities */
|
data/ext/iodine/evio.c
CHANGED
|
@@ -10,33 +10,8 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
|
10
10
|
|
|
11
11
|
#include "evio.h"
|
|
12
12
|
|
|
13
|
-
#if !defined(__unix__) && !defined(__linux__) && !defined(__APPLE__) && \
|
|
14
|
-
!defined(__CYGWIN__)
|
|
15
|
-
#error This library currently supports only Unix based systems (i.e. Linux and BSD)
|
|
16
|
-
#endif
|
|
17
|
-
|
|
18
|
-
#include <assert.h>
|
|
19
|
-
#include <errno.h>
|
|
20
|
-
#include <fcntl.h>
|
|
21
|
-
#include <netdb.h>
|
|
22
|
-
#include <stdint.h>
|
|
23
13
|
#include <stdio.h>
|
|
24
14
|
#include <stdlib.h>
|
|
25
|
-
#include <string.h>
|
|
26
|
-
#include <sys/socket.h>
|
|
27
|
-
#include <sys/time.h>
|
|
28
|
-
#include <sys/types.h>
|
|
29
|
-
#include <time.h>
|
|
30
|
-
#include <unistd.h>
|
|
31
|
-
|
|
32
|
-
/*
|
|
33
|
-
#define EVIO_MAX_EVENTS 64
|
|
34
|
-
#define EVIO_TICK 256
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
#if (EVIO_MAX_EVENTS & 1) || EVIO_MAX_EVENTS < 3
|
|
38
|
-
#error EVIO_MAX_EVENTS must be an even number higher than 4
|
|
39
|
-
#endif
|
|
40
15
|
|
|
41
16
|
/* *****************************************************************************
|
|
42
17
|
Callbacks - weak versions to be overridden.
|
|
@@ -49,238 +24,3 @@ void __attribute__((weak)) evio_on_ready(void *arg) { (void)arg; }
|
|
|
49
24
|
void __attribute__((weak)) evio_on_error(void *arg) { (void)arg; }
|
|
50
25
|
#pragma weak evio_on_close
|
|
51
26
|
void __attribute__((weak)) evio_on_close(void *arg) { (void)arg; }
|
|
52
|
-
|
|
53
|
-
/* *****************************************************************************
|
|
54
|
-
Global data and system independant code
|
|
55
|
-
***************************************************************************** */
|
|
56
|
-
|
|
57
|
-
static int evio_fd = -1;
|
|
58
|
-
|
|
59
|
-
/** Closes the `epoll` / `kqueue` object, releasing it's resources. */
|
|
60
|
-
void evio_close() {
|
|
61
|
-
if (evio_fd != -1)
|
|
62
|
-
close(evio_fd);
|
|
63
|
-
evio_fd = -1;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
returns true if the evio is available for adding or removing file descriptors.
|
|
68
|
-
*/
|
|
69
|
-
int evio_isactive(void) { return evio_fd >= 0; }
|
|
70
|
-
|
|
71
|
-
#if defined(__linux__) || defined(__CYGWIN__)
|
|
72
|
-
/* *****************************************************************************
|
|
73
|
-
Linux `epoll` implementation
|
|
74
|
-
***************************************************************************** */
|
|
75
|
-
#include <sys/epoll.h>
|
|
76
|
-
#include <sys/timerfd.h>
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
Creates the `epoll` or `kqueue` object.
|
|
80
|
-
*/
|
|
81
|
-
intptr_t evio_create() { return evio_fd = epoll_create1(EPOLL_CLOEXEC); }
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
Removes a file descriptor from the polling object.
|
|
85
|
-
*/
|
|
86
|
-
int evio_remove(int fd) {
|
|
87
|
-
struct epoll_event chevent = {0};
|
|
88
|
-
return epoll_ctl(evio_fd, EPOLL_CTL_DEL, fd, &chevent);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
Adds a file descriptor to the polling object.
|
|
93
|
-
*/
|
|
94
|
-
int evio_add(int fd, void *callback_arg) {
|
|
95
|
-
struct epoll_event chevent = {0};
|
|
96
|
-
chevent.data.ptr = (void *)callback_arg;
|
|
97
|
-
chevent.events = EPOLLOUT | EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLHUP;
|
|
98
|
-
return epoll_ctl(evio_fd, EPOLL_CTL_ADD, fd, &chevent);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
Creates a timer file descriptor, system dependent.
|
|
103
|
-
*/
|
|
104
|
-
intptr_t evio_open_timer(void) {
|
|
105
|
-
#ifndef TFD_NONBLOCK
|
|
106
|
-
intptr_t fd = timerfd_create(CLOCK_MONOTONIC, O_NONBLOCK);
|
|
107
|
-
if (fd != -1) { /* make sure it's a non-blocking timer. */
|
|
108
|
-
#if defined(O_NONBLOCK)
|
|
109
|
-
/* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
|
|
110
|
-
int flags;
|
|
111
|
-
if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
|
|
112
|
-
flags = 0;
|
|
113
|
-
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
|
|
114
|
-
goto error;
|
|
115
|
-
#else
|
|
116
|
-
/* no O_NONBLOCK, use the old way of doing it */
|
|
117
|
-
static int flags = 1;
|
|
118
|
-
if (ioctl(fd, FIOBIO, &flags) == -1)
|
|
119
|
-
goto error;
|
|
120
|
-
#endif
|
|
121
|
-
}
|
|
122
|
-
return fd;
|
|
123
|
-
error:
|
|
124
|
-
close(fd);
|
|
125
|
-
return -1;
|
|
126
|
-
#else
|
|
127
|
-
return timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
|
128
|
-
#endif
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
Adds a timer file descriptor, so that callbacks will be called for it's events.
|
|
133
|
-
*/
|
|
134
|
-
intptr_t evio_add_timer(int fd, void *callback_arg,
|
|
135
|
-
unsigned long milliseconds) {
|
|
136
|
-
struct epoll_event chevent = {.data.ptr = (void *)callback_arg,
|
|
137
|
-
.events = (EPOLLIN | EPOLLET)};
|
|
138
|
-
struct itimerspec new_t_data;
|
|
139
|
-
new_t_data.it_value.tv_sec = new_t_data.it_interval.tv_sec =
|
|
140
|
-
milliseconds / 1000;
|
|
141
|
-
new_t_data.it_value.tv_nsec = new_t_data.it_interval.tv_nsec =
|
|
142
|
-
(milliseconds % 1000) * 1000000;
|
|
143
|
-
if (timerfd_settime(fd, 0, &new_t_data, NULL) == -1)
|
|
144
|
-
return -1;
|
|
145
|
-
int ret = epoll_ctl(evio_fd, EPOLL_CTL_ADD, fd, &chevent);
|
|
146
|
-
if (ret == -1 && errno == EEXIST)
|
|
147
|
-
return 0;
|
|
148
|
-
return ret;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/** Rearms the timer. Required only by `epoll`.*/
|
|
152
|
-
void evio_reset_timer(int timer_fd) {
|
|
153
|
-
char data[8]; // void * is 8 byte long
|
|
154
|
-
if (read(timer_fd, &data, 8) < 0)
|
|
155
|
-
data[0] = 0;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
Reviews any pending events (up to EVIO_MAX_EVENTS) and calls any callbacks.
|
|
160
|
-
*/
|
|
161
|
-
int evio_review(const int timeout_millisec) {
|
|
162
|
-
if (evio_fd < 0)
|
|
163
|
-
return -1;
|
|
164
|
-
struct epoll_event events[EVIO_MAX_EVENTS];
|
|
165
|
-
/* wait for events and handle them */
|
|
166
|
-
int active_count =
|
|
167
|
-
epoll_wait(evio_fd, events, EVIO_MAX_EVENTS, timeout_millisec);
|
|
168
|
-
|
|
169
|
-
if (active_count > 0) {
|
|
170
|
-
for (int i = 0; i < active_count; i++) {
|
|
171
|
-
if (events[i].events & (~(EPOLLIN | EPOLLOUT))) {
|
|
172
|
-
// errors are hendled as disconnections (on_close)
|
|
173
|
-
evio_on_error(events[i].data.ptr);
|
|
174
|
-
} else {
|
|
175
|
-
// no error, then it's an active event(s)
|
|
176
|
-
if (events[i].events & EPOLLOUT) {
|
|
177
|
-
evio_on_ready(events[i].data.ptr);
|
|
178
|
-
}
|
|
179
|
-
if (events[i].events & EPOLLIN)
|
|
180
|
-
evio_on_data(events[i].data.ptr);
|
|
181
|
-
}
|
|
182
|
-
} // end for loop
|
|
183
|
-
} else if (active_count < 0) {
|
|
184
|
-
return -1;
|
|
185
|
-
}
|
|
186
|
-
return active_count;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
#else
|
|
190
|
-
/* *****************************************************************************
|
|
191
|
-
BSD `kqueue` implementation
|
|
192
|
-
***************************************************************************** */
|
|
193
|
-
#include <sys/event.h>
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
Creates the `epoll` or `kqueue` object.
|
|
197
|
-
*/
|
|
198
|
-
intptr_t evio_create() { return evio_fd = kqueue(); }
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
Removes a file descriptor from the polling object.
|
|
202
|
-
*/
|
|
203
|
-
int evio_remove(int fd) {
|
|
204
|
-
struct kevent chevent[3];
|
|
205
|
-
EV_SET(chevent, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
|
|
206
|
-
EV_SET(chevent + 1, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
|
|
207
|
-
EV_SET(chevent + 2, fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
|
|
208
|
-
return kevent(evio_fd, chevent, 3, NULL, 0, NULL);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
Adds a file descriptor to the polling object.
|
|
213
|
-
*/
|
|
214
|
-
int evio_add(int fd, void *callback_arg) {
|
|
215
|
-
struct kevent chevent[2];
|
|
216
|
-
EV_SET(chevent, fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0,
|
|
217
|
-
callback_arg);
|
|
218
|
-
EV_SET(chevent + 1, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0,
|
|
219
|
-
callback_arg);
|
|
220
|
-
return kevent(evio_fd, chevent, 2, NULL, 0, NULL);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
Creates a timer file descriptor, system dependent.
|
|
225
|
-
*/
|
|
226
|
-
intptr_t evio_open_timer() {
|
|
227
|
-
#ifdef P_tmpdir
|
|
228
|
-
char template[] = P_tmpdir "evio_facil_timer_XXXXXX";
|
|
229
|
-
#else
|
|
230
|
-
char template[] = "/tmp/evio_facil_timer_XXXXXX";
|
|
231
|
-
#endif
|
|
232
|
-
return mkstemp(template);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
Adds a timer file descriptor, so that callbacks will be called for it's events.
|
|
237
|
-
*/
|
|
238
|
-
intptr_t evio_add_timer(int fd, void *callback_arg,
|
|
239
|
-
unsigned long milliseconds) {
|
|
240
|
-
struct kevent chevent;
|
|
241
|
-
EV_SET(&chevent, fd, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, milliseconds,
|
|
242
|
-
callback_arg);
|
|
243
|
-
return kevent(evio_fd, &chevent, 1, NULL, 0, NULL);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/** Rearms the timer. Required only by `epoll`.*/
|
|
247
|
-
void evio_reset_timer(int timer_fd) { (void)timer_fd; }
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
Reviews any pending events (up to EVIO_MAX_EVENTS) and calls any callbacks.
|
|
251
|
-
*/
|
|
252
|
-
int evio_review(const int timeout_millisec) {
|
|
253
|
-
if (evio_fd < 0)
|
|
254
|
-
return -1;
|
|
255
|
-
struct kevent events[EVIO_MAX_EVENTS];
|
|
256
|
-
|
|
257
|
-
const struct timespec timeout = {.tv_sec = (timeout_millisec / 1024),
|
|
258
|
-
.tv_nsec =
|
|
259
|
-
((timeout_millisec % 1024) * 1000000)};
|
|
260
|
-
/* wait for events and handle them */
|
|
261
|
-
int active_count =
|
|
262
|
-
kevent(evio_fd, NULL, 0, events, EVIO_MAX_EVENTS, &timeout);
|
|
263
|
-
|
|
264
|
-
if (active_count > 0) {
|
|
265
|
-
for (int i = 0; i < active_count; i++) {
|
|
266
|
-
if (events[i].flags & (EV_EOF | EV_ERROR)) {
|
|
267
|
-
// errors are hendled as disconnections (on_close)
|
|
268
|
-
evio_on_error(events[i].udata);
|
|
269
|
-
} else {
|
|
270
|
-
// no error, then it's an active event(s)
|
|
271
|
-
if (events[i].filter == EVFILT_WRITE) {
|
|
272
|
-
evio_on_ready(events[i].udata);
|
|
273
|
-
}
|
|
274
|
-
if (events[i].filter == EVFILT_READ || events[i].filter == EVFILT_TIMER)
|
|
275
|
-
evio_on_data(events[i].udata);
|
|
276
|
-
}
|
|
277
|
-
} // end for loop
|
|
278
|
-
} else if (active_count < 0) {
|
|
279
|
-
if (errno == EINTR)
|
|
280
|
-
return 0;
|
|
281
|
-
return -1;
|
|
282
|
-
}
|
|
283
|
-
return active_count;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
#endif /* system dependent code */
|
data/ext/iodine/evio.h
CHANGED
|
@@ -9,9 +9,9 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
|
9
9
|
#include <stdlib.h>
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
This is an `epoll` / `kqueue`
|
|
13
|
-
between BSD and Linux polling machanisms
|
|
14
|
-
callbacks (weak function symbols)
|
|
12
|
+
This is an `epoll` / `kqueue` ONE-SHOT polling wrapper, allowing for portability
|
|
13
|
+
between BSD and Linux polling machanisms and routing events to hard-coded
|
|
14
|
+
callbacks (weak function symbols).
|
|
15
15
|
|
|
16
16
|
The callbacks supported by thils library:
|
|
17
17
|
|
|
@@ -23,8 +23,16 @@ The callbacks supported by thils library:
|
|
|
23
23
|
*/
|
|
24
24
|
#define H_FACIL_EVIO_H
|
|
25
25
|
#define LIB_EVIO_VERSION_MAJOR 0
|
|
26
|
-
#define LIB_EVIO_VERSION_MINOR
|
|
27
|
-
#define LIB_EVIO_VERSION_PATCH
|
|
26
|
+
#define LIB_EVIO_VERSION_MINOR 2
|
|
27
|
+
#define LIB_EVIO_VERSION_PATCH 0
|
|
28
|
+
|
|
29
|
+
#if defined(__linux__)
|
|
30
|
+
#define EVIO_ENGINE_EPOLL 1
|
|
31
|
+
#elif defined(__APPLE__) || defined(__unix__)
|
|
32
|
+
#define EVIO_ENGINE_KQUEUE 1
|
|
33
|
+
#else
|
|
34
|
+
#error This library currently supports only Unix based systems with kqueue or epoll (i.e. Linux and BSD)
|
|
35
|
+
#endif
|
|
28
36
|
|
|
29
37
|
#ifdef __cplusplus
|
|
30
38
|
extern "C" {
|
|
@@ -34,7 +42,14 @@ extern "C" {
|
|
|
34
42
|
#define EVIO_MAX_EVENTS 64
|
|
35
43
|
#endif
|
|
36
44
|
#ifndef EVIO_TICK
|
|
37
|
-
#define EVIO_TICK
|
|
45
|
+
#define EVIO_TICK 512 /** in milliseconsd */
|
|
46
|
+
#endif
|
|
47
|
+
|
|
48
|
+
#if (EVIO_MAX_EVENTS & 1)
|
|
49
|
+
#error EVIO_MAX_EVENTS must be an EVEN number.
|
|
50
|
+
#endif
|
|
51
|
+
#if EVIO_MAX_EVENTS <= 3
|
|
52
|
+
#error EVIO_MAX_EVENTS must be an GREATER than 4.
|
|
38
53
|
#endif
|
|
39
54
|
|
|
40
55
|
/**
|
|
@@ -61,8 +76,12 @@ Returns -1 on error, otherwise returns the number of events handled.
|
|
|
61
76
|
*/
|
|
62
77
|
int evio_review(const int timeout_millisec);
|
|
63
78
|
|
|
79
|
+
/** Waits up to `timeout_millisec` for events. Events aren't reviewed. */
|
|
80
|
+
int evio_wait(const int timeout_millisec);
|
|
81
|
+
|
|
64
82
|
/**
|
|
65
|
-
Closes the `epoll` / `kqueue` object, releasing it's resources
|
|
83
|
+
Closes the `epoll` / `kqueue` object, releasing it's resources (important if
|
|
84
|
+
forking!).
|
|
66
85
|
*/
|
|
67
86
|
void evio_close(void);
|
|
68
87
|
|
|
@@ -72,11 +91,12 @@ returns true if the evio is available for adding or removing file descriptors.
|
|
|
72
91
|
int evio_isactive(void);
|
|
73
92
|
|
|
74
93
|
/* *****************************************************************************
|
|
75
|
-
Adding and removing normal file descriptors.
|
|
94
|
+
Adding and removing normal file descriptors (ONE SHOT).
|
|
76
95
|
*/
|
|
77
96
|
|
|
78
97
|
/**
|
|
79
|
-
Adds a file descriptor to the polling object
|
|
98
|
+
Adds a file descriptor to the polling object (ONE SHOT), both for read / write
|
|
99
|
+
readiness.
|
|
80
100
|
|
|
81
101
|
Returns -1 on error, otherwise return value is system dependent and can be
|
|
82
102
|
safely ignored.
|
|
@@ -84,12 +104,27 @@ safely ignored.
|
|
|
84
104
|
int evio_add(int fd, void *callback_arg);
|
|
85
105
|
|
|
86
106
|
/**
|
|
87
|
-
|
|
107
|
+
Adds a file descriptor to the polling object (ONE SHOT), to be polled for
|
|
108
|
+
incoming data (`evio_on_data` wil be called).
|
|
109
|
+
|
|
110
|
+
Returns -1 on error, otherwise return value is system dependent and can be
|
|
111
|
+
safely ignored.
|
|
112
|
+
*/
|
|
113
|
+
int evio_add_read(int fd, void *callback_arg);
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
Adds a file descriptor to the polling object (ONE SHOT), to be polled for
|
|
117
|
+
outgoing buffer readiness data (`evio_on_ready` wil be called).
|
|
88
118
|
|
|
89
|
-
Returns -1 on error, otherwise return value is system dependent
|
|
90
|
-
|
|
119
|
+
Returns -1 on error, otherwise return value is system dependent and can be
|
|
120
|
+
safely ignored.
|
|
91
121
|
*/
|
|
92
|
-
int
|
|
122
|
+
int evio_add_write(int fd, void *callback_arg);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
Removes a file descriptor from the polling object.
|
|
126
|
+
*/
|
|
127
|
+
void evio_remove(int fd);
|
|
93
128
|
|
|
94
129
|
/* *****************************************************************************
|
|
95
130
|
Timers.
|
|
@@ -102,21 +137,14 @@ Returns -1 on error, or a valid fd on success.
|
|
|
102
137
|
|
|
103
138
|
NOTE: Systems have a limit on the number of timers that can be opened.
|
|
104
139
|
*/
|
|
105
|
-
|
|
140
|
+
int evio_open_timer(void);
|
|
106
141
|
|
|
107
142
|
/**
|
|
108
143
|
Adds a timer file descriptor, so that callbacks will be called for it's events.
|
|
109
144
|
|
|
110
145
|
Returns -1 on error, otherwise return value is system dependent.
|
|
111
146
|
*/
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
Re-arms the timer.
|
|
116
|
-
|
|
117
|
-
Required only by `epoll`. `kqueue` timers will continue cycling regardless.
|
|
118
|
-
*/
|
|
119
|
-
void evio_reset_timer(int timer_fd);
|
|
147
|
+
int evio_set_timer(int fd, void *callback_arg, unsigned long milliseconds);
|
|
120
148
|
|
|
121
149
|
/* *****************************************************************************
|
|
122
150
|
Callbacks - override these.
|