eio 0.1
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.
- data/.gitignore +8 -0
- data/COPYING +502 -0
- data/LICENSE +16 -0
- data/README.rdoc +201 -0
- data/Rakefile +48 -0
- data/bench/eventmachine.rb +134 -0
- data/eio.gemspec +17 -0
- data/ext/eio/eio_ext.c +1447 -0
- data/ext/eio/extconf.rb +11 -0
- data/ext/libeio/CVS/Entries +13 -0
- data/ext/libeio/CVS/Repository +1 -0
- data/ext/libeio/CVS/Root +1 -0
- data/ext/libeio/Changes +40 -0
- data/ext/libeio/LICENSE +36 -0
- data/ext/libeio/Makefile +692 -0
- data/ext/libeio/Makefile.am +15 -0
- data/ext/libeio/Makefile.in +692 -0
- data/ext/libeio/aclocal.m4 +8937 -0
- data/ext/libeio/autogen.sh +3 -0
- data/ext/libeio/autom4te.cache/output.0 +13871 -0
- data/ext/libeio/autom4te.cache/output.1 +13867 -0
- data/ext/libeio/autom4te.cache/requests +275 -0
- data/ext/libeio/autom4te.cache/traces.0 +2384 -0
- data/ext/libeio/autom4te.cache/traces.1 +621 -0
- data/ext/libeio/config.guess +1501 -0
- data/ext/libeio/config.h +122 -0
- data/ext/libeio/config.h.in +121 -0
- data/ext/libeio/config.status +2035 -0
- data/ext/libeio/config.sub +1705 -0
- data/ext/libeio/configure +13867 -0
- data/ext/libeio/configure.ac +22 -0
- data/ext/libeio/demo.c +194 -0
- data/ext/libeio/eio.3 +3428 -0
- data/ext/libeio/eio.c +2075 -0
- data/ext/libeio/eio.h +336 -0
- data/ext/libeio/eio.pod +303 -0
- data/ext/libeio/install-sh +520 -0
- data/ext/libeio/libeio.m4 +156 -0
- data/ext/libeio/libtool +8890 -0
- data/ext/libeio/ltmain.sh +8406 -0
- data/ext/libeio/missing +376 -0
- data/ext/libeio/stamp-h1 +1 -0
- data/ext/libeio/xthread.h +168 -0
- data/lib/eio.rb +9 -0
- data/lib/eio/eventmachine.rb +24 -0
- data/lib/eio/middleware.rb +21 -0
- data/test/test_eio.rb +1161 -0
- data/test/test_eventmachine.rb +23 -0
- data/test/test_middleware.rb +20 -0
- metadata +148 -0
data/ext/libeio/eio.h
ADDED
@@ -0,0 +1,336 @@
|
|
1
|
+
/*
|
2
|
+
* libeio API header
|
3
|
+
*
|
4
|
+
* Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libeio@schmorp.de>
|
5
|
+
* All rights reserved.
|
6
|
+
*
|
7
|
+
* Redistribution and use in source and binary forms, with or without modifica-
|
8
|
+
* tion, are permitted provided that the following conditions are met:
|
9
|
+
*
|
10
|
+
* 1. Redistributions of source code must retain the above copyright notice,
|
11
|
+
* this list of conditions and the following disclaimer.
|
12
|
+
*
|
13
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
* notice, this list of conditions and the following disclaimer in the
|
15
|
+
* documentation and/or other materials provided with the distribution.
|
16
|
+
*
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
18
|
+
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
19
|
+
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
20
|
+
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
21
|
+
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
23
|
+
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
24
|
+
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
25
|
+
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
26
|
+
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
*
|
28
|
+
* Alternatively, the contents of this file may be used under the terms of
|
29
|
+
* the GNU General Public License ("GPL") version 2 or any later version,
|
30
|
+
* in which case the provisions of the GPL are applicable instead of
|
31
|
+
* the above. If you wish to allow the use of your version of this file
|
32
|
+
* only under the terms of the GPL and not to allow others to use your
|
33
|
+
* version of this file under the BSD license, indicate your decision
|
34
|
+
* by deleting the provisions above and replace them with the notice
|
35
|
+
* and other provisions required by the GPL. If you do not delete the
|
36
|
+
* provisions above, a recipient may use your version of this file under
|
37
|
+
* either the BSD or the GPL.
|
38
|
+
*/
|
39
|
+
|
40
|
+
#ifndef EIO_H_
|
41
|
+
#define EIO_H_
|
42
|
+
|
43
|
+
#ifdef __cplusplus
|
44
|
+
extern "C" {
|
45
|
+
#endif
|
46
|
+
|
47
|
+
#include <stddef.h>
|
48
|
+
#include <sys/types.h>
|
49
|
+
|
50
|
+
typedef struct eio_req eio_req;
|
51
|
+
typedef struct eio_dirent eio_dirent;
|
52
|
+
|
53
|
+
typedef int (*eio_cb)(eio_req *req);
|
54
|
+
|
55
|
+
#ifndef EIO_REQ_MEMBERS
|
56
|
+
# define EIO_REQ_MEMBERS
|
57
|
+
#endif
|
58
|
+
|
59
|
+
#ifndef EIO_STRUCT_STAT
|
60
|
+
# define EIO_STRUCT_STAT struct stat
|
61
|
+
#endif
|
62
|
+
|
63
|
+
#ifndef EIO_STRUCT_STATVFS
|
64
|
+
# define EIO_STRUCT_STATVFS struct statvfs
|
65
|
+
#endif
|
66
|
+
|
67
|
+
/* for readdir */
|
68
|
+
|
69
|
+
/* eio_readdir flags */
|
70
|
+
enum
|
71
|
+
{
|
72
|
+
EIO_READDIR_DENTS = 0x01, /* ptr2 contains eio_dirents, not just the (unsorted) names */
|
73
|
+
EIO_READDIR_DIRS_FIRST = 0x02, /* dirents gets sorted into a good stat() ing order to find directories first */
|
74
|
+
EIO_READDIR_STAT_ORDER = 0x04, /* dirents gets sorted into a good stat() ing order to quickly stat all files */
|
75
|
+
EIO_READDIR_FOUND_UNKNOWN = 0x80, /* set by eio_readdir when *_ARRAY was set and any TYPE=UNKNOWN's were found */
|
76
|
+
|
77
|
+
EIO_READDIR_CUSTOM1 = 0x100, /* for use by apps */
|
78
|
+
EIO_READDIR_CUSTOM2 = 0x200 /* for use by apps */
|
79
|
+
};
|
80
|
+
|
81
|
+
/* using "typical" values in the hope that the compiler will do something sensible */
|
82
|
+
enum eio_dtype
|
83
|
+
{
|
84
|
+
EIO_DT_UNKNOWN = 0,
|
85
|
+
EIO_DT_FIFO = 1,
|
86
|
+
EIO_DT_CHR = 2,
|
87
|
+
EIO_DT_MPC = 3, /* multiplexed char device (v7+coherent) */
|
88
|
+
EIO_DT_DIR = 4,
|
89
|
+
EIO_DT_NAM = 5, /* xenix special named file */
|
90
|
+
EIO_DT_BLK = 6,
|
91
|
+
EIO_DT_MPB = 7, /* multiplexed block device (v7+coherent) */
|
92
|
+
EIO_DT_REG = 8,
|
93
|
+
EIO_DT_NWK = 9, /* HP-UX network special */
|
94
|
+
EIO_DT_CMP = 9, /* VxFS compressed */
|
95
|
+
EIO_DT_LNK = 10,
|
96
|
+
/* DT_SHAD = 11,*/
|
97
|
+
EIO_DT_SOCK = 12,
|
98
|
+
EIO_DT_DOOR = 13, /* solaris door */
|
99
|
+
EIO_DT_WHT = 14,
|
100
|
+
EIO_DT_MAX = 15 /* highest DT_VALUE ever, hopefully */
|
101
|
+
};
|
102
|
+
|
103
|
+
struct eio_dirent
|
104
|
+
{
|
105
|
+
int nameofs; /* offset of null-terminated name string in (char *)req->ptr2 */
|
106
|
+
unsigned short namelen; /* size of filename without trailing 0 */
|
107
|
+
unsigned char type; /* one of EIO_DT_* */
|
108
|
+
signed char score; /* internal use */
|
109
|
+
ino_t inode; /* the inode number, if available, otherwise unspecified */
|
110
|
+
};
|
111
|
+
|
112
|
+
/* eio_msync flags */
|
113
|
+
enum
|
114
|
+
{
|
115
|
+
EIO_MS_ASYNC = 1,
|
116
|
+
EIO_MS_INVALIDATE = 2,
|
117
|
+
EIO_MS_SYNC = 4
|
118
|
+
};
|
119
|
+
|
120
|
+
/* eio_mtouch flags */
|
121
|
+
|
122
|
+
enum
|
123
|
+
{
|
124
|
+
EIO_MT_MODIFY = 1
|
125
|
+
};
|
126
|
+
|
127
|
+
/* eio_sync_file_range flags */
|
128
|
+
|
129
|
+
enum
|
130
|
+
{
|
131
|
+
EIO_SYNC_FILE_RANGE_WAIT_BEFORE = 1,
|
132
|
+
EIO_SYNC_FILE_RANGE_WRITE = 2,
|
133
|
+
EIO_SYNC_FILE_RANGE_WAIT_AFTER = 4
|
134
|
+
};
|
135
|
+
|
136
|
+
typedef double eio_tstamp; /* feel free to use double in your code directly */
|
137
|
+
|
138
|
+
/* the eio request structure */
|
139
|
+
|
140
|
+
enum
|
141
|
+
{
|
142
|
+
EIO_CUSTOM,
|
143
|
+
EIO_OPEN, EIO_CLOSE, EIO_DUP2,
|
144
|
+
EIO_READ, EIO_WRITE,
|
145
|
+
EIO_READAHEAD, EIO_SENDFILE,
|
146
|
+
EIO_STAT, EIO_LSTAT, EIO_FSTAT,
|
147
|
+
EIO_STATVFS, EIO_FSTATVFS,
|
148
|
+
EIO_TRUNCATE, EIO_FTRUNCATE,
|
149
|
+
EIO_UTIME, EIO_FUTIME,
|
150
|
+
EIO_CHMOD, EIO_FCHMOD,
|
151
|
+
EIO_CHOWN, EIO_FCHOWN,
|
152
|
+
EIO_SYNC, EIO_FSYNC, EIO_FDATASYNC,
|
153
|
+
EIO_MSYNC, EIO_MTOUCH, EIO_SYNC_FILE_RANGE,
|
154
|
+
EIO_MLOCK, EIO_MLOCKALL,
|
155
|
+
EIO_UNLINK, EIO_RMDIR, EIO_MKDIR, EIO_RENAME,
|
156
|
+
EIO_MKNOD, EIO_READDIR,
|
157
|
+
EIO_LINK, EIO_SYMLINK, EIO_READLINK,
|
158
|
+
EIO_GROUP, EIO_NOP,
|
159
|
+
EIO_BUSY
|
160
|
+
};
|
161
|
+
|
162
|
+
/* mlockall constants */
|
163
|
+
enum
|
164
|
+
{
|
165
|
+
EIO_MCL_CURRENT = 1,
|
166
|
+
EIO_MCL_FUTURE = 2,
|
167
|
+
};
|
168
|
+
|
169
|
+
/* request priorities */
|
170
|
+
|
171
|
+
enum {
|
172
|
+
EIO_PRI_MIN = -4,
|
173
|
+
EIO_PRI_MAX = 4,
|
174
|
+
EIO_PRI_DEFAULT = 0,
|
175
|
+
};
|
176
|
+
|
177
|
+
/* eio request structure */
|
178
|
+
/* this structure is mostly read-only */
|
179
|
+
/* when initialising it, all members must be zero-initialised */
|
180
|
+
struct eio_req
|
181
|
+
{
|
182
|
+
eio_req volatile *next; /* private ETP */
|
183
|
+
|
184
|
+
ssize_t result; /* result of syscall, e.g. result = read (... */
|
185
|
+
off_t offs; /* read, write, truncate, readahead, sync_file_range: file offset, mknod: dev_t */
|
186
|
+
size_t size; /* read, write, readahead, sendfile, msync, mlock, sync_file_range: length */
|
187
|
+
void *ptr1; /* all applicable requests: pathname, old name; readdir: optional eio_dirents */
|
188
|
+
void *ptr2; /* all applicable requests: new name or memory buffer; readdir: name strings */
|
189
|
+
eio_tstamp nv1; /* utime, futime: atime; busy: sleep time */
|
190
|
+
eio_tstamp nv2; /* utime, futime: mtime */
|
191
|
+
|
192
|
+
int type; /* EIO_xxx constant ETP */
|
193
|
+
int int1; /* all applicable requests: file descriptor; sendfile: output fd; open, msync, mlockall, readdir: flags */
|
194
|
+
long int2; /* chown, fchown: uid; sendfile: input fd; open, chmod, mkdir, mknod: file mode, sync_file_range: flags */
|
195
|
+
long int3; /* chown, fchown: gid */
|
196
|
+
int errorno; /* errno value on syscall return */
|
197
|
+
|
198
|
+
unsigned char flags; /* private */
|
199
|
+
signed char pri; /* the priority */
|
200
|
+
|
201
|
+
void *data;
|
202
|
+
eio_cb finish;
|
203
|
+
void (*destroy)(eio_req *req); /* called when requets no longer needed */
|
204
|
+
void (*feed)(eio_req *req); /* only used for group requests */
|
205
|
+
|
206
|
+
EIO_REQ_MEMBERS
|
207
|
+
|
208
|
+
eio_req *grp, *grp_prev, *grp_next, *grp_first; /* private */
|
209
|
+
};
|
210
|
+
|
211
|
+
/* _private_ request flags */
|
212
|
+
enum {
|
213
|
+
EIO_FLAG_CANCELLED = 0x01, /* request was cancelled */
|
214
|
+
EIO_FLAG_PTR1_FREE = 0x02, /* need to free(ptr1) */
|
215
|
+
EIO_FLAG_PTR2_FREE = 0x04, /* need to free(ptr2) */
|
216
|
+
EIO_FLAG_GROUPADD = 0x08 /* some request was added to the group */
|
217
|
+
};
|
218
|
+
|
219
|
+
/* undocumented/unsupported/private helper */
|
220
|
+
/*void eio_page_align (void **addr, size_t *length);*/
|
221
|
+
|
222
|
+
/* returns < 0 on error, errno set
|
223
|
+
* need_poll, if non-zero, will be called when results are available
|
224
|
+
* and eio_poll_cb needs to be invoked (it MUST NOT call eio_poll_cb itself).
|
225
|
+
* done_poll is called when the need to poll is gone.
|
226
|
+
*/
|
227
|
+
int eio_init (void (*want_poll)(void), void (*done_poll)(void));
|
228
|
+
|
229
|
+
/* must be called regularly to handle pending requests */
|
230
|
+
/* returns 0 if all requests were handled, -1 if not, or the value of EIO_FINISH if != 0 */
|
231
|
+
int eio_poll (void);
|
232
|
+
|
233
|
+
/* stop polling if poll took longer than duration seconds */
|
234
|
+
void eio_set_max_poll_time (eio_tstamp nseconds);
|
235
|
+
/* do not handle more then count requests in one call to eio_poll_cb */
|
236
|
+
void eio_set_max_poll_reqs (unsigned int nreqs);
|
237
|
+
|
238
|
+
/* set minimum required number
|
239
|
+
* maximum wanted number
|
240
|
+
* or maximum idle number of threads */
|
241
|
+
void eio_set_min_parallel (unsigned int nthreads);
|
242
|
+
void eio_set_max_parallel (unsigned int nthreads);
|
243
|
+
void eio_set_max_idle (unsigned int nthreads);
|
244
|
+
void eio_set_idle_timeout (unsigned int seconds);
|
245
|
+
|
246
|
+
unsigned int eio_nreqs (void); /* number of requests in-flight */
|
247
|
+
unsigned int eio_nready (void); /* number of not-yet handled requests */
|
248
|
+
unsigned int eio_npending (void); /* numbe rof finished but unhandled requests */
|
249
|
+
unsigned int eio_nthreads (void); /* number of worker threads in use currently */
|
250
|
+
|
251
|
+
/*****************************************************************************/
|
252
|
+
/* convinience wrappers */
|
253
|
+
|
254
|
+
#ifndef EIO_NO_WRAPPERS
|
255
|
+
eio_req *eio_nop (int pri, eio_cb cb, void *data); /* does nothing except go through the whole process */
|
256
|
+
eio_req *eio_busy (eio_tstamp delay, int pri, eio_cb cb, void *data); /* ties a thread for this long, simulating busyness */
|
257
|
+
eio_req *eio_sync (int pri, eio_cb cb, void *data);
|
258
|
+
eio_req *eio_fsync (int fd, int pri, eio_cb cb, void *data);
|
259
|
+
eio_req *eio_fdatasync (int fd, int pri, eio_cb cb, void *data);
|
260
|
+
eio_req *eio_msync (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data);
|
261
|
+
eio_req *eio_mtouch (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data);
|
262
|
+
eio_req *eio_mlock (void *addr, size_t length, int pri, eio_cb cb, void *data);
|
263
|
+
eio_req *eio_mlockall (int flags, int pri, eio_cb cb, void *data);
|
264
|
+
eio_req *eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data);
|
265
|
+
eio_req *eio_close (int fd, int pri, eio_cb cb, void *data);
|
266
|
+
eio_req *eio_readahead (int fd, off_t offset, size_t length, int pri, eio_cb cb, void *data);
|
267
|
+
eio_req *eio_read (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data);
|
268
|
+
eio_req *eio_write (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data);
|
269
|
+
eio_req *eio_fstat (int fd, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */
|
270
|
+
eio_req *eio_fstatvfs (int fd, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */
|
271
|
+
eio_req *eio_futime (int fd, eio_tstamp atime, eio_tstamp mtime, int pri, eio_cb cb, void *data);
|
272
|
+
eio_req *eio_ftruncate (int fd, off_t offset, int pri, eio_cb cb, void *data);
|
273
|
+
eio_req *eio_fchmod (int fd, mode_t mode, int pri, eio_cb cb, void *data);
|
274
|
+
eio_req *eio_fchown (int fd, uid_t uid, gid_t gid, int pri, eio_cb cb, void *data);
|
275
|
+
eio_req *eio_dup2 (int fd, int fd2, int pri, eio_cb cb, void *data);
|
276
|
+
eio_req *eio_sendfile (int out_fd, int in_fd, off_t in_offset, size_t length, int pri, eio_cb cb, void *data);
|
277
|
+
eio_req *eio_open (const char *path, int flags, mode_t mode, int pri, eio_cb cb, void *data);
|
278
|
+
eio_req *eio_utime (const char *path, eio_tstamp atime, eio_tstamp mtime, int pri, eio_cb cb, void *data);
|
279
|
+
eio_req *eio_truncate (const char *path, off_t offset, int pri, eio_cb cb, void *data);
|
280
|
+
eio_req *eio_chown (const char *path, uid_t uid, gid_t gid, int pri, eio_cb cb, void *data);
|
281
|
+
eio_req *eio_chmod (const char *path, mode_t mode, int pri, eio_cb cb, void *data);
|
282
|
+
eio_req *eio_mkdir (const char *path, mode_t mode, int pri, eio_cb cb, void *data);
|
283
|
+
eio_req *eio_readdir (const char *path, int flags, int pri, eio_cb cb, void *data); /* result=ptr2 allocated dynamically */
|
284
|
+
eio_req *eio_rmdir (const char *path, int pri, eio_cb cb, void *data);
|
285
|
+
eio_req *eio_unlink (const char *path, int pri, eio_cb cb, void *data);
|
286
|
+
eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data); /* result=ptr2 allocated dynamically */
|
287
|
+
eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */
|
288
|
+
eio_req *eio_lstat (const char *path, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */
|
289
|
+
eio_req *eio_statvfs (const char *path, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */
|
290
|
+
eio_req *eio_mknod (const char *path, mode_t mode, dev_t dev, int pri, eio_cb cb, void *data);
|
291
|
+
eio_req *eio_link (const char *path, const char *new_path, int pri, eio_cb cb, void *data);
|
292
|
+
eio_req *eio_symlink (const char *path, const char *new_path, int pri, eio_cb cb, void *data);
|
293
|
+
eio_req *eio_rename (const char *path, const char *new_path, int pri, eio_cb cb, void *data);
|
294
|
+
eio_req *eio_custom (eio_cb execute, int pri, eio_cb cb, void *data);
|
295
|
+
#endif
|
296
|
+
|
297
|
+
/*****************************************************************************/
|
298
|
+
/* groups */
|
299
|
+
|
300
|
+
eio_req *eio_grp (eio_cb cb, void *data);
|
301
|
+
void eio_grp_feed (eio_req *grp, void (*feed)(eio_req *req), int limit);
|
302
|
+
void eio_grp_limit (eio_req *grp, int limit);
|
303
|
+
void eio_grp_add (eio_req *grp, eio_req *req);
|
304
|
+
void eio_grp_cancel (eio_req *grp); /* cancels all sub requests but not the group */
|
305
|
+
|
306
|
+
/*****************************************************************************/
|
307
|
+
/* request api */
|
308
|
+
|
309
|
+
/* true if the request was cancelled, useful in the invoke callback */
|
310
|
+
#define EIO_CANCELLED(req) ((req)->flags & EIO_FLAG_CANCELLED)
|
311
|
+
|
312
|
+
#define EIO_RESULT(req) ((req)->result)
|
313
|
+
/* returns a pointer to the result buffer allocated by eio */
|
314
|
+
#define EIO_BUF(req) ((req)->ptr2)
|
315
|
+
#define EIO_STAT_BUF(req) ((EIO_STRUCT_STAT *)EIO_BUF(req))
|
316
|
+
#define EIO_STATVFS_BUF(req) ((EIO_STRUCT_STATVFS *)EIO_BUF(req))
|
317
|
+
#define EIO_PATH(req) ((char *)(req)->ptr1)
|
318
|
+
|
319
|
+
/* submit a request for execution */
|
320
|
+
void eio_submit (eio_req *req);
|
321
|
+
/* cancel a request as soon fast as possible, if possible */
|
322
|
+
void eio_cancel (eio_req *req);
|
323
|
+
/* destroy a request that has never been submitted */
|
324
|
+
void eio_destroy (eio_req *req);
|
325
|
+
|
326
|
+
/*****************************************************************************/
|
327
|
+
/* convinience functions */
|
328
|
+
|
329
|
+
ssize_t eio_sendfile_sync (int ofd, int ifd, off_t offset, size_t count);
|
330
|
+
|
331
|
+
#ifdef __cplusplus
|
332
|
+
}
|
333
|
+
#endif
|
334
|
+
|
335
|
+
#endif
|
336
|
+
|
data/ext/libeio/eio.pod
ADDED
@@ -0,0 +1,303 @@
|
|
1
|
+
=head1 NAME
|
2
|
+
|
3
|
+
libeio - truly asynchronous POSIX I/O
|
4
|
+
|
5
|
+
=head1 SYNOPSIS
|
6
|
+
|
7
|
+
#include <eio.h>
|
8
|
+
|
9
|
+
=head1 DESCRIPTION
|
10
|
+
|
11
|
+
The newest version of this document is also available as an html-formatted
|
12
|
+
web page you might find easier to navigate when reading it for the first
|
13
|
+
time: L<http://pod.tst.eu/http://cvs.schmorp.de/libeio/eio.pod>.
|
14
|
+
|
15
|
+
Note that this library is a by-product of the C<IO::AIO> perl
|
16
|
+
module, and many of the subtler points regarding requests lifetime
|
17
|
+
and so on are only documented in its documentation at the
|
18
|
+
moment: L<http://pod.tst.eu/http://cvs.schmorp.de/IO-AIO/AIO.pm>.
|
19
|
+
|
20
|
+
=head2 FEATURES
|
21
|
+
|
22
|
+
This library provides fully asynchronous versions of most POSIX functions
|
23
|
+
dealing with I/O. Unlike most asynchronous libraries, this not only
|
24
|
+
includes C<read> and C<write>, but also C<open>, C<stat>, C<unlink> and
|
25
|
+
similar functions, as well as less rarely ones such as C<mknod>, C<futime>
|
26
|
+
or C<readlink>.
|
27
|
+
|
28
|
+
It also offers wrappers around C<sendfile> (Solaris, Linux, HP-UX and
|
29
|
+
FreeBSD, with emulation on other platforms) and C<readahead> (Linux, with
|
30
|
+
emulation elsewhere>).
|
31
|
+
|
32
|
+
The goal is to enable you to write fully non-blocking programs. For
|
33
|
+
example, in a game server, you would not want to freeze for a few seconds
|
34
|
+
just because the server is running a backup and you happen to call
|
35
|
+
C<readdir>.
|
36
|
+
|
37
|
+
=head2 TIME REPRESENTATION
|
38
|
+
|
39
|
+
Libeio represents time as a single floating point number, representing the
|
40
|
+
(fractional) number of seconds since the (POSIX) epoch (somewhere near
|
41
|
+
the beginning of 1970, details are complicated, don't ask). This type is
|
42
|
+
called C<eio_tstamp>, but it is guaranteed to be of type C<double> (or
|
43
|
+
better), so you can freely use C<double> yourself.
|
44
|
+
|
45
|
+
Unlike the name component C<stamp> might indicate, it is also used for
|
46
|
+
time differences throughout libeio.
|
47
|
+
|
48
|
+
=head2 FORK SUPPORT
|
49
|
+
|
50
|
+
Calling C<fork ()> is fully supported by this module. It is implemented in these steps:
|
51
|
+
|
52
|
+
1. wait till all requests in "execute" state have been handled
|
53
|
+
(basically requests that are already handed over to the kernel).
|
54
|
+
2. fork
|
55
|
+
3. in the parent, continue business as usual, done
|
56
|
+
4. in the child, destroy all ready and pending requests and free the
|
57
|
+
memory used by the worker threads. This gives you a fully empty
|
58
|
+
libeio queue.
|
59
|
+
|
60
|
+
=head1 INITIALISATION/INTEGRATION
|
61
|
+
|
62
|
+
Before you can call any eio functions you first have to initialise the
|
63
|
+
library. The library integrates into any event loop, but can also be used
|
64
|
+
without one, including in polling mode.
|
65
|
+
|
66
|
+
You have to provide the necessary glue yourself, however.
|
67
|
+
|
68
|
+
=over 4
|
69
|
+
|
70
|
+
=item int eio_init (void (*want_poll)(void), void (*done_poll)(void))
|
71
|
+
|
72
|
+
This function initialises the library. On success it returns C<0>, on
|
73
|
+
failure it returns C<-1> and sets C<errno> appropriately.
|
74
|
+
|
75
|
+
It accepts two function pointers specifying callbacks as argument, both of
|
76
|
+
which can be C<0>, in which case the callback isn't called.
|
77
|
+
|
78
|
+
=item want_poll callback
|
79
|
+
|
80
|
+
The C<want_poll> callback is invoked whenever libeio wants attention (i.e.
|
81
|
+
it wants to be polled by calling C<eio_poll>). It is "edge-triggered",
|
82
|
+
that is, it will only be called once when eio wants attention, until all
|
83
|
+
pending requests have been handled.
|
84
|
+
|
85
|
+
This callback is called while locks are being held, so I<you must
|
86
|
+
not call any libeio functions inside this callback>. That includes
|
87
|
+
C<eio_poll>. What you should do is notify some other thread, or wake up
|
88
|
+
your event loop, and then call C<eio_poll>.
|
89
|
+
|
90
|
+
=item done_poll callback
|
91
|
+
|
92
|
+
This callback is invoked when libeio detects that all pending requests
|
93
|
+
have been handled. It is "edge-triggered", that is, it will only be
|
94
|
+
called once after C<want_poll>. To put it differently, C<want_poll> and
|
95
|
+
C<done_poll> are invoked in pairs: after C<want_poll> you have to call
|
96
|
+
C<eio_poll ()> until either C<eio_poll> indicates that everything has been
|
97
|
+
handled or C<done_poll> has been called, which signals the same.
|
98
|
+
|
99
|
+
Note that C<eio_poll> might return after C<done_poll> and C<want_poll>
|
100
|
+
have been called again, so watch out for races in your code.
|
101
|
+
|
102
|
+
As with C<want_poll>, this callback is called while locks are being held,
|
103
|
+
so you I<must not call any libeio functions form within this callback>.
|
104
|
+
|
105
|
+
=item int eio_poll ()
|
106
|
+
|
107
|
+
This function has to be called whenever there are pending requests that
|
108
|
+
need finishing. You usually call this after C<want_poll> has indicated
|
109
|
+
that you should do so, but you can also call this function regularly to
|
110
|
+
poll for new results.
|
111
|
+
|
112
|
+
If any request invocation returns a non-zero value, then C<eio_poll ()>
|
113
|
+
immediately returns with that value as return value.
|
114
|
+
|
115
|
+
Otherwise, if all requests could be handled, it returns C<0>. If for some
|
116
|
+
reason not all requests have been handled, i.e. some are still pending, it
|
117
|
+
returns C<-1>.
|
118
|
+
|
119
|
+
=back
|
120
|
+
|
121
|
+
For libev, you would typically use an C<ev_async> watcher: the
|
122
|
+
C<want_poll> callback would invoke C<ev_async_send> to wake up the event
|
123
|
+
loop. Inside the callback set for the watcher, one would call C<eio_poll
|
124
|
+
()> (followed by C<ev_async_send> again if C<eio_poll> indicates that not
|
125
|
+
all requests have been handled yet). The race is taken care of because
|
126
|
+
libev resets/rearms the async watcher before calling your callback,
|
127
|
+
and therefore, before calling C<eio_poll>. This might result in (some)
|
128
|
+
spurious wake-ups, but is generally harmless.
|
129
|
+
|
130
|
+
For most other event loops, you would typically use a pipe - the event
|
131
|
+
loop should be told to wait for read readiness on the read end. In
|
132
|
+
C<want_poll> you would write a single byte, in C<done_poll> you would try
|
133
|
+
to read that byte, and in the callback for the read end, you would call
|
134
|
+
C<eio_poll>. The race is avoided here because the event loop should invoke
|
135
|
+
your callback again and again until the byte has been read (as the pipe
|
136
|
+
read callback does not read it, only C<done_poll>).
|
137
|
+
|
138
|
+
=head2 CONFIGURATION
|
139
|
+
|
140
|
+
The functions in this section can sometimes be useful, but the default
|
141
|
+
configuration will do in most case, so you should skip this section on
|
142
|
+
first reading.
|
143
|
+
|
144
|
+
=over 4
|
145
|
+
|
146
|
+
=item eio_set_max_poll_time (eio_tstamp nseconds)
|
147
|
+
|
148
|
+
This causes C<eio_poll ()> to return after it has detected that it was
|
149
|
+
running for C<nsecond> seconds or longer (this number can be fractional).
|
150
|
+
|
151
|
+
This can be used to limit the amount of time spent handling eio requests,
|
152
|
+
for example, in interactive programs, you might want to limit this time to
|
153
|
+
C<0.01> seconds or so.
|
154
|
+
|
155
|
+
Note that:
|
156
|
+
|
157
|
+
a) libeio doesn't know how long your request callbacks take, so the time
|
158
|
+
spent in C<eio_poll> is up to one callback invocation longer then this
|
159
|
+
interval.
|
160
|
+
|
161
|
+
b) this is implemented by calling C<gettimeofday> after each request,
|
162
|
+
which can be costly.
|
163
|
+
|
164
|
+
c) at least one request will be handled.
|
165
|
+
|
166
|
+
=item eio_set_max_poll_reqs (unsigned int nreqs)
|
167
|
+
|
168
|
+
When C<nreqs> is non-zero, then C<eio_poll> will not handle more than
|
169
|
+
C<nreqs> requests per invocation. This is a less costly way to limit the
|
170
|
+
amount of work done by C<eio_poll> then setting a time limit.
|
171
|
+
|
172
|
+
If you know your callbacks are generally fast, you could use this to
|
173
|
+
encourage interactiveness in your programs by setting it to C<10>, C<100>
|
174
|
+
or even C<1000>.
|
175
|
+
|
176
|
+
=item eio_set_min_parallel (unsigned int nthreads)
|
177
|
+
|
178
|
+
Make sure libeio can handle at least this many requests in parallel. It
|
179
|
+
might be able handle more.
|
180
|
+
|
181
|
+
=item eio_set_max_parallel (unsigned int nthreads)
|
182
|
+
|
183
|
+
Set the maximum number of threads that libeio will spawn.
|
184
|
+
|
185
|
+
=item eio_set_max_idle (unsigned int nthreads)
|
186
|
+
|
187
|
+
Libeio uses threads internally to handle most requests, and will start and stop threads on demand.
|
188
|
+
|
189
|
+
This call can be used to limit the number of idle threads (threads without
|
190
|
+
work to do): libeio will keep some threads idle in preparation for more
|
191
|
+
requests, but never longer than C<nthreads> threads.
|
192
|
+
|
193
|
+
In addition to this, libeio will also stop threads when they are idle for
|
194
|
+
a few seconds, regardless of this setting.
|
195
|
+
|
196
|
+
=item unsigned int eio_nthreads ()
|
197
|
+
|
198
|
+
Return the number of worker threads currently running.
|
199
|
+
|
200
|
+
=item unsigned int eio_nreqs ()
|
201
|
+
|
202
|
+
Return the number of requests currently handled by libeio. This is the
|
203
|
+
total number of requests that have been submitted to libeio, but not yet
|
204
|
+
destroyed.
|
205
|
+
|
206
|
+
=item unsigned int eio_nready ()
|
207
|
+
|
208
|
+
Returns the number of ready requests, i.e. requests that have been
|
209
|
+
submitted but have not yet entered the execution phase.
|
210
|
+
|
211
|
+
=item unsigned int eio_npending ()
|
212
|
+
|
213
|
+
Returns the number of pending requests, i.e. requests that have been
|
214
|
+
executed and have results, but have not been finished yet by a call to
|
215
|
+
C<eio_poll>).
|
216
|
+
|
217
|
+
=back
|
218
|
+
|
219
|
+
|
220
|
+
=head1 ANATOMY OF AN EIO REQUEST
|
221
|
+
|
222
|
+
#TODO
|
223
|
+
|
224
|
+
|
225
|
+
=head1 HIGH LEVEL REQUEST API
|
226
|
+
|
227
|
+
#TODO
|
228
|
+
|
229
|
+
=back
|
230
|
+
|
231
|
+
|
232
|
+
=head1 LOW LEVEL REQUEST API
|
233
|
+
|
234
|
+
#TODO
|
235
|
+
|
236
|
+
=head1 EMBEDDING
|
237
|
+
|
238
|
+
Libeio can be embedded directly into programs. This functionality is not
|
239
|
+
documented and not (yet) officially supported.
|
240
|
+
|
241
|
+
Note that, when including C<libeio.m4>, you are responsible for defining
|
242
|
+
the compilation environment (C<_LARGEFILE_SOURCE>, C<_GNU_SOURCE> etc.).
|
243
|
+
|
244
|
+
If you need to know how, check the C<IO::AIO> perl module, which does
|
245
|
+
exactly that.
|
246
|
+
|
247
|
+
|
248
|
+
=head1 COMPILETIME CONFIGURATION
|
249
|
+
|
250
|
+
These symbols, if used, must be defined when compiling F<eio.c>.
|
251
|
+
|
252
|
+
=over 4
|
253
|
+
|
254
|
+
=item EIO_STACKSIZE
|
255
|
+
|
256
|
+
This symbol governs the stack size for each eio thread. Libeio itself
|
257
|
+
was written to use very little stackspace, but when using C<EIO_CUSTOM>
|
258
|
+
requests, you might want to increase this.
|
259
|
+
|
260
|
+
If this symbol is undefined (the default) then libeio will use its default
|
261
|
+
stack size (C<sizeof (long) * 4096> currently). If it is defined, but
|
262
|
+
C<0>, then the default operating system stack size will be used. In all
|
263
|
+
other cases, the value must be an expression that evaluates to the desired
|
264
|
+
stack size.
|
265
|
+
|
266
|
+
=back
|
267
|
+
|
268
|
+
|
269
|
+
=head1 PORTABILITY REQUIREMENTS
|
270
|
+
|
271
|
+
In addition to a working ISO-C implementation, libeio relies on a few
|
272
|
+
additional extensions:
|
273
|
+
|
274
|
+
=over 4
|
275
|
+
|
276
|
+
=item POSIX threads
|
277
|
+
|
278
|
+
To be portable, this module uses threads, specifically, the POSIX threads
|
279
|
+
library must be available (and working, which partially excludes many xBSD
|
280
|
+
systems, where C<fork ()> is buggy).
|
281
|
+
|
282
|
+
=item POSIX-compatible filesystem API
|
283
|
+
|
284
|
+
This is actually a harder portability requirement: The libeio API is quite
|
285
|
+
demanding regarding POSIX API calls (symlinks, user/group management
|
286
|
+
etc.).
|
287
|
+
|
288
|
+
=item C<double> must hold a time value in seconds with enough accuracy
|
289
|
+
|
290
|
+
The type C<double> is used to represent timestamps. It is required to
|
291
|
+
have at least 51 bits of mantissa (and 9 bits of exponent), which is good
|
292
|
+
enough for at least into the year 4000. This requirement is fulfilled by
|
293
|
+
implementations implementing IEEE 754 (basically all existing ones).
|
294
|
+
|
295
|
+
=back
|
296
|
+
|
297
|
+
If you know of other additional requirements drop me a note.
|
298
|
+
|
299
|
+
|
300
|
+
=head1 AUTHOR
|
301
|
+
|
302
|
+
Marc Lehmann <libeio@schmorp.de>.
|
303
|
+
|