You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

aio_event.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /* Copyright (c) 2010-2011, Vsevolod Stakhov
  2. * All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. * * Redistributions of source code must retain the above copyright
  7. * notice, this list of conditions and the following disclaimer.
  8. * * Redistributions in binary form must reproduce the above copyright
  9. * notice, this list of conditions and the following disclaimer in the
  10. * documentation and/or other materials provided with the distribution.
  11. *
  12. * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
  13. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  16. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #include "config.h"
  24. #include "aio_event.h"
  25. #include "main.h"
  26. #ifdef HAVE_SYS_EVENTFD_H
  27. #include <sys/eventfd.h>
  28. #endif
  29. #ifdef HAVE_AIO_H
  30. #include <aio.h>
  31. #endif
  32. /* Linux syscall numbers */
  33. #if defined(__i386__)
  34. # define SYS_io_setup 245
  35. # define SYS_io_destroy 246
  36. # define SYS_io_getevents 247
  37. # define SYS_io_submit 248
  38. # define SYS_io_cancel 249
  39. #elif defined(__x86_64__)
  40. # define SYS_io_setup 206
  41. # define SYS_io_destroy 207
  42. # define SYS_io_getevents 208
  43. # define SYS_io_submit 209
  44. # define SYS_io_cancel 210
  45. #else
  46. # warning "aio is not supported on this platform, please contact author for details"
  47. # define SYS_io_setup 0
  48. # define SYS_io_destroy 0
  49. # define SYS_io_getevents 0
  50. # define SYS_io_submit 0
  51. # define SYS_io_cancel 0
  52. #endif
  53. #define SYS_eventfd 323
  54. #define MAX_AIO_EV 64
  55. struct io_cbdata {
  56. gint fd;
  57. rspamd_aio_cb cb;
  58. guint64 len;
  59. gpointer buf;
  60. gpointer io_buf;
  61. gpointer ud;
  62. };
  63. #ifdef LINUX
  64. /* Linux specific mappings and utilities to avoid using of libaio */
  65. typedef unsigned long aio_context_t;
  66. typedef enum io_iocb_cmd {
  67. IO_CMD_PREAD = 0,
  68. IO_CMD_PWRITE = 1,
  69. IO_CMD_FSYNC = 2,
  70. IO_CMD_FDSYNC = 3,
  71. IO_CMD_POLL = 5,
  72. IO_CMD_NOOP = 6,
  73. } io_iocb_cmd_t;
  74. #if defined(__LITTLE_ENDIAN)
  75. #define PADDED(x,y) x, y
  76. #elif defined(__BIG_ENDIAN)
  77. #define PADDED(x,y) y, x
  78. #else
  79. #error edit for your odd byteorder.
  80. #endif
  81. /*
  82. * we always use a 64bit off_t when communicating
  83. * with userland. its up to libraries to do the
  84. * proper padding and aio_error abstraction
  85. */
  86. struct iocb {
  87. /* these are internal to the kernel/libc. */
  88. guint64 aio_data; /* data to be returned in event's data */
  89. guint32 PADDED(aio_key, aio_reserved1);
  90. /* the kernel sets aio_key to the req # */
  91. /* common fields */
  92. guint16 aio_lio_opcode; /* see IOCB_CMD_ above */
  93. gint16 aio_reqprio;
  94. guint32 aio_fildes;
  95. guint64 aio_buf;
  96. guint64 aio_nbytes;
  97. gint64 aio_offset;
  98. /* extra parameters */
  99. guint64 aio_reserved2; /* TODO: use this for a (struct sigevent *) */
  100. /* flags for the "struct iocb" */
  101. guint32 aio_flags;
  102. /*
  103. * if the IOCB_FLAG_RESFD flag of "aio_flags" is set, this is an
  104. * eventfd to signal AIO readiness to
  105. */
  106. guint32 aio_resfd;
  107. };
  108. struct io_event {
  109. guint64 data; /* the data field from the iocb */
  110. guint64 obj; /* what iocb this event came from */
  111. gint64 res; /* result code for this event */
  112. gint64 res2; /* secondary result */
  113. };
  114. /* Linux specific io calls */
  115. static int
  116. io_setup (guint nr_reqs, aio_context_t *ctx)
  117. {
  118. return syscall (SYS_io_setup, nr_reqs, ctx);
  119. }
  120. static int
  121. io_destroy (aio_context_t ctx)
  122. {
  123. return syscall (SYS_io_destroy, ctx);
  124. }
  125. static int
  126. io_getevents (aio_context_t ctx, long min_nr, long nr, struct io_event *events, struct timespec *tmo)
  127. {
  128. return syscall (SYS_io_getevents, ctx, min_nr, nr, events, tmo);
  129. }
  130. static int
  131. io_submit (aio_context_t ctx, long n, struct iocb **paiocb)
  132. {
  133. return syscall (SYS_io_submit, ctx, n, paiocb);
  134. }
  135. static int
  136. io_cancel (aio_context_t ctx, struct iocb *iocb, struct io_event *result)
  137. {
  138. return syscall (SYS_io_cancel, ctx, iocb, result);
  139. }
  140. # ifndef HAVE_SYS_EVENTFD_H
  141. static int
  142. eventfd (guint initval, guint flags)
  143. {
  144. return syscall (SYS_eventfd, initval);
  145. }
  146. # endif
  147. #endif
  148. /**
  149. * AIO context
  150. */
  151. struct aio_context {
  152. struct event_base *base;
  153. gboolean has_aio; /**< Whether we have aio support on a system */
  154. #ifdef LINUX
  155. /* Eventfd variant */
  156. gint event_fd;
  157. struct event eventfd_ev;
  158. aio_context_t io_ctx;
  159. #elif defined(HAVE_AIO_H)
  160. /* POSIX aio */
  161. struct event rtsigs[128];
  162. #endif
  163. };
  164. #ifdef LINUX
  165. /* Eventfd read callback */
  166. static void
  167. rspamd_eventfdcb (gint fd, gshort what, gpointer ud)
  168. {
  169. struct aio_context *ctx = ud;
  170. guint64 ready;
  171. gint done, i;
  172. struct io_event event[32];
  173. struct timespec ts;
  174. struct io_cbdata *ev_data;
  175. /* Eventfd returns number of events ready got from kernel */
  176. if (read (fd, &ready, 8) != 8) {
  177. if (errno == EAGAIN) {
  178. return;
  179. }
  180. msg_err ("eventfd read returned error: %s", strerror (errno));
  181. }
  182. ts.tv_sec = 0;
  183. ts.tv_nsec = 0;
  184. while (ready) {
  185. /* Get events ready */
  186. done = io_getevents (ctx->io_ctx, 1, 32, event, &ts);
  187. if (done > 0) {
  188. ready -= done;
  189. for (i = 0; i < done; i ++) {
  190. ev_data = (struct io_cbdata *) (uintptr_t) event[i].data;
  191. /* Call this callback */
  192. ev_data->cb (ev_data->fd, event[i].res, ev_data->len, ev_data->buf, ev_data->ud);
  193. if (ev_data->io_buf) {
  194. free (ev_data->io_buf);
  195. }
  196. g_slice_free1 (sizeof (struct io_cbdata), ev_data);
  197. }
  198. }
  199. else if (done == 0) {
  200. /* No more events are ready */
  201. return;
  202. }
  203. else {
  204. msg_err ("io_getevents failed: %s", strerror (errno));
  205. return;
  206. }
  207. }
  208. }
  209. #endif
  210. /**
  211. * Initialize aio with specified event base
  212. */
  213. struct aio_context*
  214. rspamd_aio_init (struct event_base *base)
  215. {
  216. struct aio_context *new;
  217. /* First of all we need to detect which type of aio we can try to use */
  218. new = g_malloc0 (sizeof (struct aio_context));
  219. new->base = base;
  220. #ifdef LINUX
  221. /* On linux we are trying to use io (3) and eventfd for notifying */
  222. new->event_fd = eventfd (0, 0);
  223. if (new->event_fd == -1) {
  224. msg_err ("eventfd failed: %s", strerror (errno));
  225. }
  226. else {
  227. /* Set this socket non-blocking */
  228. if (make_socket_nonblocking (new->event_fd) == -1) {
  229. msg_err ("non blocking for eventfd failed: %s", strerror (errno));
  230. close (new->event_fd);
  231. }
  232. else {
  233. event_set (&new->eventfd_ev, new->event_fd, EV_READ|EV_PERSIST, rspamd_eventfdcb, new);
  234. event_base_set (new->base, &new->eventfd_ev);
  235. event_add (&new->eventfd_ev, NULL);
  236. if (io_setup (MAX_AIO_EV, &new->io_ctx) == -1) {
  237. msg_err ("io_setup failed: %s", strerror (errno));
  238. close (new->event_fd);
  239. }
  240. else {
  241. new->has_aio = TRUE;
  242. }
  243. }
  244. }
  245. #elif defined(HAVE_AIO_H)
  246. /* TODO: implement this */
  247. #endif
  248. return new;
  249. }
  250. /**
  251. * Open file for aio
  252. */
  253. gint
  254. rspamd_aio_open (struct aio_context *ctx, const gchar *path, int flags)
  255. {
  256. gint fd = -1;
  257. /* Fallback */
  258. if (!ctx->has_aio) {
  259. return open (path, flags);
  260. }
  261. #ifdef LINUX
  262. fd = open (path, flags | O_DIRECT);
  263. return fd;
  264. #elif defined(HAVE_AIO_H)
  265. fd = open (path, flags);
  266. #endif
  267. return fd;
  268. }
  269. /**
  270. * Asynchronous read of file
  271. */
  272. gint
  273. rspamd_aio_read (gint fd, gpointer buf, guint64 len, guint64 offset, struct aio_context *ctx, rspamd_aio_cb cb, gpointer ud)
  274. {
  275. struct io_cbdata *cbdata;
  276. gint r = -1;
  277. if (ctx->has_aio) {
  278. #ifdef LINUX
  279. struct iocb *iocb[1];
  280. cbdata = g_slice_alloc (sizeof (struct io_cbdata));
  281. cbdata->cb = cb;
  282. cbdata->buf = buf;
  283. cbdata->len = len;
  284. cbdata->ud = ud;
  285. cbdata->fd = fd;
  286. cbdata->io_buf = NULL;
  287. iocb[0] = alloca (sizeof (struct iocb));
  288. memset (iocb[0], 0, sizeof (struct iocb));
  289. iocb[0]->aio_fildes = fd;
  290. iocb[0]->aio_lio_opcode = IO_CMD_PREAD;
  291. iocb[0]->aio_reqprio = 0;
  292. iocb[0]->aio_buf = (guint64)((uintptr_t)buf);
  293. iocb[0]->aio_nbytes = len;
  294. iocb[0]->aio_offset = offset;
  295. iocb[0]->aio_flags |= (1 << 0) /* IOCB_FLAG_RESFD */;
  296. iocb[0]->aio_resfd = ctx->event_fd;
  297. iocb[0]->aio_data = (guint64)((uintptr_t)cbdata);
  298. /* Iocb is copied to kernel internally, so it is safe to put it on stack */
  299. if (io_submit (ctx->io_ctx, 1, iocb) == 1) {
  300. return len;
  301. }
  302. else {
  303. if (errno == EAGAIN || errno == ENOSYS) {
  304. /* Fall back to sync read */
  305. goto blocking;
  306. }
  307. return -1;
  308. }
  309. #elif defined(HAVE_AIO_H)
  310. #endif
  311. }
  312. else {
  313. /* Blocking variant */
  314. blocking:
  315. #ifdef _LARGEFILE64_SOURCE
  316. r = lseek64 (fd, offset, SEEK_SET);
  317. #else
  318. r = lseek (fd, offset, SEEK_SET);
  319. #endif
  320. if (r > 0) {
  321. r = read (fd, buf, len);
  322. if (r >= 0) {
  323. cb (fd, 0, r, buf, ud);
  324. }
  325. else {
  326. cb (fd, r, -1, buf, ud);
  327. }
  328. }
  329. }
  330. return r;
  331. }
  332. /**
  333. * Asynchronous write of file
  334. */
  335. gint
  336. rspamd_aio_write (gint fd, gpointer buf, guint64 len, guint64 offset, struct aio_context *ctx, rspamd_aio_cb cb, gpointer ud)
  337. {
  338. struct io_cbdata *cbdata;
  339. gint r = -1;
  340. if (ctx->has_aio) {
  341. #ifdef LINUX
  342. struct iocb *iocb[1];
  343. cbdata = g_slice_alloc (sizeof (struct io_cbdata));
  344. cbdata->cb = cb;
  345. cbdata->buf = buf;
  346. cbdata->len = len;
  347. cbdata->ud = ud;
  348. cbdata->fd = fd;
  349. /* We need to align pointer on boundary of 512 bytes here */
  350. if (posix_memalign (&cbdata->io_buf, 512, len) != 0) {
  351. return -1;
  352. }
  353. memcpy (cbdata->io_buf, buf, len);
  354. iocb[0] = alloca (sizeof (struct iocb));
  355. memset (iocb[0], 0, sizeof (struct iocb));
  356. iocb[0]->aio_fildes = fd;
  357. iocb[0]->aio_lio_opcode = IO_CMD_PWRITE;
  358. iocb[0]->aio_reqprio = 0;
  359. iocb[0]->aio_buf = (guint64)((uintptr_t)cbdata->io_buf);
  360. iocb[0]->aio_nbytes = len;
  361. iocb[0]->aio_offset = offset;
  362. iocb[0]->aio_flags |= (1 << 0) /* IOCB_FLAG_RESFD */;
  363. iocb[0]->aio_resfd = ctx->event_fd;
  364. iocb[0]->aio_data = (guint64)((uintptr_t)cbdata);
  365. /* Iocb is copied to kernel internally, so it is safe to put it on stack */
  366. if (io_submit (ctx->io_ctx, 1, iocb) == 1) {
  367. return len;
  368. }
  369. else {
  370. if (errno == EAGAIN || errno == ENOSYS) {
  371. /* Fall back to sync read */
  372. goto blocking;
  373. }
  374. return -1;
  375. }
  376. #elif defined(HAVE_AIO_H)
  377. #endif
  378. }
  379. else {
  380. /* Blocking variant */
  381. blocking:
  382. #ifdef _LARGEFILE64_SOURCE
  383. r = lseek64 (fd, offset, SEEK_SET);
  384. #else
  385. r = lseek (fd, offset, SEEK_SET);
  386. #endif
  387. if (r > 0) {
  388. r = write (fd, buf, len);
  389. if (r >= 0) {
  390. cb (fd, 0, r, buf, ud);
  391. }
  392. else {
  393. cb (fd, r, -1, buf, ud);
  394. }
  395. }
  396. }
  397. return r;
  398. }
  399. /**
  400. * Close of aio operations
  401. */
  402. gint
  403. rspamd_aio_close (gint fd, struct aio_context *ctx)
  404. {
  405. gint r = -1;
  406. if (ctx->has_aio) {
  407. #ifdef LINUX
  408. struct iocb iocb;
  409. struct io_event ev;
  410. memset (&iocb, 0, sizeof (struct iocb));
  411. iocb.aio_fildes = fd;
  412. iocb.aio_lio_opcode = IO_CMD_NOOP;
  413. /* Iocb is copied to kernel internally, so it is safe to put it on stack */
  414. r = io_cancel (ctx->io_ctx, &iocb, &ev);
  415. close (fd);
  416. return r;
  417. #elif defined(HAVE_AIO_H)
  418. #endif
  419. }
  420. r = close (fd);
  421. return r;
  422. }