polyphony 0.93 → 0.95
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/.github/workflows/test.yml +2 -2
- data/.gitignore +3 -3
- data/CHANGELOG.md +14 -0
- data/docs/api-reference/fiber.md +2 -2
- data/docs/api-reference/object.md +3 -3
- data/docs/main-concepts/exception-handling.md +2 -2
- data/examples/pipes/echo_server.rb +1 -1
- data/examples/pipes/http_server.rb +33 -0
- data/ext/polyphony/backend_common.c +53 -8
- data/ext/polyphony/backend_common.h +21 -13
- data/ext/polyphony/backend_io_uring.c +85 -147
- data/ext/polyphony/backend_libev.c +58 -89
- data/ext/polyphony/event.c +1 -1
- data/ext/polyphony/extconf.rb +7 -5
- data/ext/polyphony/fiber.c +5 -13
- data/ext/polyphony/io_extensions.c +68 -68
- data/ext/polyphony/pipe.c +1 -1
- data/ext/polyphony/polyphony.c +23 -23
- data/ext/polyphony/polyphony.h +0 -9
- data/ext/polyphony/polyphony_ext.c +1 -1
- data/ext/polyphony/queue.c +1 -1
- data/ext/polyphony/ring_buffer.c +1 -0
- data/ext/polyphony/socket_extensions.c +1 -1
- data/ext/polyphony/thread.c +1 -1
- data/lib/polyphony/extensions/enumerator.rb +16 -0
- data/lib/polyphony/extensions/socket.rb +2 -0
- data/lib/polyphony/extensions.rb +1 -0
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +2 -2
- data/test/test_backend.rb +5 -1
- data/test/test_enumerator.rb +46 -0
- data/test/test_global_api.rb +1 -1
- data/test/test_io.rb +241 -216
- data/test/test_socket.rb +1 -1
- data/test/test_thread_pool.rb +3 -3
- data/vendor/liburing/.github/workflows/build.yml +51 -5
- data/vendor/liburing/.github/workflows/shellcheck.yml +1 -1
- data/vendor/liburing/.gitignore +6 -123
- data/vendor/liburing/CHANGELOG +35 -0
- data/vendor/liburing/CITATION.cff +11 -0
- data/vendor/liburing/LICENSE +16 -3
- data/vendor/liburing/Makefile +3 -1
- data/vendor/liburing/Makefile.common +1 -0
- data/vendor/liburing/README +14 -2
- data/vendor/liburing/SECURITY.md +6 -0
- data/vendor/liburing/configure +16 -15
- data/vendor/liburing/examples/Makefile +4 -1
- data/vendor/liburing/examples/io_uring-udp.c +395 -0
- data/vendor/liburing/examples/poll-bench.c +101 -0
- data/vendor/liburing/examples/send-zerocopy.c +339 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/man/io_uring.7 +38 -11
- data/vendor/liburing/man/io_uring_buf_ring_add.3 +53 -0
- data/vendor/liburing/man/io_uring_buf_ring_advance.3 +31 -0
- data/vendor/liburing/man/io_uring_buf_ring_cq_advance.3 +41 -0
- data/vendor/liburing/man/io_uring_buf_ring_init.3 +30 -0
- data/vendor/liburing/man/io_uring_buf_ring_mask.3 +27 -0
- data/vendor/liburing/man/io_uring_cq_advance.3 +29 -15
- data/vendor/liburing/man/io_uring_cq_has_overflow.3 +25 -0
- data/vendor/liburing/man/io_uring_cq_ready.3 +9 -8
- data/vendor/liburing/man/io_uring_cqe_get_data.3 +32 -13
- data/vendor/liburing/man/io_uring_cqe_get_data64.3 +1 -0
- data/vendor/liburing/man/io_uring_cqe_seen.3 +22 -12
- data/vendor/liburing/man/io_uring_enter.2 +249 -32
- data/vendor/liburing/man/io_uring_enter2.2 +1 -0
- data/vendor/liburing/man/io_uring_free_probe.3 +11 -8
- data/vendor/liburing/man/io_uring_get_events.3 +33 -0
- data/vendor/liburing/man/io_uring_get_probe.3 +9 -8
- data/vendor/liburing/man/io_uring_get_sqe.3 +29 -10
- data/vendor/liburing/man/io_uring_opcode_supported.3 +11 -10
- data/vendor/liburing/man/io_uring_peek_cqe.3 +38 -0
- data/vendor/liburing/man/io_uring_prep_accept.3 +197 -0
- data/vendor/liburing/man/io_uring_prep_accept_direct.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_cancel.3 +118 -0
- data/vendor/liburing/man/io_uring_prep_cancel64.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_close.3 +59 -0
- data/vendor/liburing/man/io_uring_prep_close_direct.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_connect.3 +66 -0
- data/vendor/liburing/man/io_uring_prep_fadvise.3 +59 -0
- data/vendor/liburing/man/io_uring_prep_fallocate.3 +59 -0
- data/vendor/liburing/man/io_uring_prep_files_update.3 +92 -0
- data/vendor/liburing/man/io_uring_prep_fsync.3 +70 -0
- data/vendor/liburing/man/io_uring_prep_link.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_linkat.3 +91 -0
- data/vendor/liburing/man/io_uring_prep_madvise.3 +56 -0
- data/vendor/liburing/man/io_uring_prep_mkdir.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_mkdirat.3 +83 -0
- data/vendor/liburing/man/io_uring_prep_msg_ring.3 +39 -25
- data/vendor/liburing/man/io_uring_prep_multishot_accept.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_multishot_accept_direct.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_nop.3 +28 -0
- data/vendor/liburing/man/io_uring_prep_openat.3 +117 -0
- data/vendor/liburing/man/io_uring_prep_openat2.3 +117 -0
- data/vendor/liburing/man/io_uring_prep_openat2_direct.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_openat_direct.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_poll_add.3 +72 -0
- data/vendor/liburing/man/io_uring_prep_poll_multishot.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_poll_remove.3 +55 -0
- data/vendor/liburing/man/io_uring_prep_poll_update.3 +89 -0
- data/vendor/liburing/man/io_uring_prep_provide_buffers.3 +131 -0
- data/vendor/liburing/man/io_uring_prep_read.3 +33 -14
- data/vendor/liburing/man/io_uring_prep_read_fixed.3 +39 -21
- data/vendor/liburing/man/io_uring_prep_readv.3 +49 -15
- data/vendor/liburing/man/io_uring_prep_readv2.3 +49 -17
- data/vendor/liburing/man/io_uring_prep_recv.3 +105 -0
- data/vendor/liburing/man/io_uring_prep_recv_multishot.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_recvmsg.3 +124 -0
- data/vendor/liburing/man/io_uring_prep_recvmsg_multishot.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_remove_buffers.3 +52 -0
- data/vendor/liburing/man/io_uring_prep_rename.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_renameat.3 +96 -0
- data/vendor/liburing/man/io_uring_prep_send.3 +57 -0
- data/vendor/liburing/man/io_uring_prep_send_zc.3 +64 -0
- data/vendor/liburing/man/io_uring_prep_sendmsg.3 +69 -0
- data/vendor/liburing/man/io_uring_prep_shutdown.3 +53 -0
- data/vendor/liburing/man/io_uring_prep_socket.3 +118 -0
- data/vendor/liburing/man/io_uring_prep_socket_direct.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_socket_direct_alloc.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_splice.3 +80 -0
- data/vendor/liburing/man/io_uring_prep_statx.3 +74 -0
- data/vendor/liburing/man/io_uring_prep_symlink.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_symlinkat.3 +85 -0
- data/vendor/liburing/man/io_uring_prep_sync_file_range.3 +59 -0
- data/vendor/liburing/man/io_uring_prep_tee.3 +74 -0
- data/vendor/liburing/man/io_uring_prep_timeout.3 +95 -0
- data/vendor/liburing/man/io_uring_prep_timeout_remove.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_timeout_update.3 +98 -0
- data/vendor/liburing/man/io_uring_prep_unlink.3 +1 -0
- data/vendor/liburing/man/io_uring_prep_unlinkat.3 +82 -0
- data/vendor/liburing/man/io_uring_prep_write.3 +32 -15
- data/vendor/liburing/man/io_uring_prep_write_fixed.3 +39 -21
- data/vendor/liburing/man/io_uring_prep_writev.3 +50 -16
- data/vendor/liburing/man/io_uring_prep_writev2.3 +50 -17
- data/vendor/liburing/man/io_uring_queue_exit.3 +3 -4
- data/vendor/liburing/man/io_uring_queue_init.3 +58 -13
- data/vendor/liburing/man/io_uring_queue_init_params.3 +1 -0
- data/vendor/liburing/man/io_uring_recvmsg_cmsg_firsthdr.3 +1 -0
- data/vendor/liburing/man/io_uring_recvmsg_cmsg_nexthdr.3 +1 -0
- data/vendor/liburing/man/io_uring_recvmsg_name.3 +1 -0
- data/vendor/liburing/man/io_uring_recvmsg_out.3 +78 -0
- data/vendor/liburing/man/io_uring_recvmsg_payload.3 +1 -0
- data/vendor/liburing/man/io_uring_recvmsg_payload_length.3 +1 -0
- data/vendor/liburing/man/io_uring_recvmsg_validate.3 +1 -0
- data/vendor/liburing/man/io_uring_register.2 +153 -13
- data/vendor/liburing/man/io_uring_register_buf_ring.3 +140 -0
- data/vendor/liburing/man/io_uring_register_buffers.3 +32 -12
- data/vendor/liburing/man/io_uring_register_eventfd.3 +51 -0
- data/vendor/liburing/man/io_uring_register_eventfd_async.3 +1 -0
- data/vendor/liburing/man/io_uring_register_file_alloc_range.3 +52 -0
- data/vendor/liburing/man/io_uring_register_files.3 +33 -11
- data/vendor/liburing/man/io_uring_register_files_sparse.3 +1 -0
- data/vendor/liburing/man/io_uring_register_iowq_aff.3 +61 -0
- data/vendor/liburing/man/io_uring_register_iowq_max_workers.3 +71 -0
- data/vendor/liburing/man/io_uring_register_ring_fd.3 +49 -0
- data/vendor/liburing/man/io_uring_register_sync_cancel.3 +71 -0
- data/vendor/liburing/man/io_uring_setup.2 +119 -13
- data/vendor/liburing/man/io_uring_sq_ready.3 +14 -8
- data/vendor/liburing/man/io_uring_sq_space_left.3 +9 -9
- data/vendor/liburing/man/io_uring_sqe_set_data.3 +29 -11
- data/vendor/liburing/man/io_uring_sqe_set_data64.3 +1 -0
- data/vendor/liburing/man/io_uring_sqe_set_flags.3 +38 -11
- data/vendor/liburing/man/io_uring_sqring_wait.3 +13 -9
- data/vendor/liburing/man/io_uring_submit.3 +29 -12
- data/vendor/liburing/man/io_uring_submit_and_get_events.3 +31 -0
- data/vendor/liburing/man/io_uring_submit_and_wait.3 +16 -12
- data/vendor/liburing/man/io_uring_submit_and_wait_timeout.3 +30 -23
- data/vendor/liburing/man/io_uring_unregister_buf_ring.3 +30 -0
- data/vendor/liburing/man/io_uring_unregister_buffers.3 +11 -10
- data/vendor/liburing/man/io_uring_unregister_eventfd.3 +1 -0
- data/vendor/liburing/man/io_uring_unregister_files.3 +11 -10
- data/vendor/liburing/man/io_uring_unregister_iowq_aff.3 +1 -0
- data/vendor/liburing/man/io_uring_unregister_ring_fd.3 +32 -0
- data/vendor/liburing/man/io_uring_wait_cqe.3 +19 -12
- data/vendor/liburing/man/io_uring_wait_cqe_nr.3 +21 -14
- data/vendor/liburing/man/io_uring_wait_cqe_timeout.3 +27 -13
- data/vendor/liburing/man/io_uring_wait_cqes.3 +24 -14
- data/vendor/liburing/src/Makefile +8 -7
- data/vendor/liburing/src/arch/aarch64/lib.h +48 -0
- data/vendor/liburing/src/arch/aarch64/syscall.h +0 -4
- data/vendor/liburing/src/arch/generic/lib.h +0 -4
- data/vendor/liburing/src/arch/generic/syscall.h +29 -16
- data/vendor/liburing/src/arch/syscall-defs.h +41 -14
- data/vendor/liburing/src/arch/x86/lib.h +0 -21
- data/vendor/liburing/src/arch/x86/syscall.h +146 -10
- data/vendor/liburing/src/include/liburing/io_uring.h +245 -5
- data/vendor/liburing/src/include/liburing.h +468 -35
- data/vendor/liburing/src/int_flags.h +1 -0
- data/vendor/liburing/src/lib.h +20 -16
- data/vendor/liburing/src/liburing.map +16 -0
- data/vendor/liburing/src/nolibc.c +1 -1
- data/vendor/liburing/src/queue.c +87 -55
- data/vendor/liburing/src/register.c +129 -53
- data/vendor/liburing/src/setup.c +65 -28
- data/vendor/liburing/src/syscall.c +14 -32
- data/vendor/liburing/src/syscall.h +12 -64
- data/vendor/liburing/test/{232c93d07b74-test.c → 232c93d07b74.c} +8 -9
- data/vendor/liburing/test/{35fa71a030ca-test.c → 35fa71a030ca.c} +4 -4
- data/vendor/liburing/test/{500f9fbadef8-test.c → 500f9fbadef8.c} +7 -7
- data/vendor/liburing/test/{7ad0e4b2f83c-test.c → 7ad0e4b2f83c.c} +8 -7
- data/vendor/liburing/test/{8a9973408177-test.c → 8a9973408177.c} +4 -3
- data/vendor/liburing/test/{917257daa0fe-test.c → 917257daa0fe.c} +3 -2
- data/vendor/liburing/test/Makefile +60 -62
- data/vendor/liburing/test/{a0908ae19763-test.c → a0908ae19763.c} +3 -2
- data/vendor/liburing/test/{a4c0b3decb33-test.c → a4c0b3decb33.c} +3 -2
- data/vendor/liburing/test/accept-link.c +5 -4
- data/vendor/liburing/test/accept-reuse.c +17 -16
- data/vendor/liburing/test/accept-test.c +14 -10
- data/vendor/liburing/test/accept.c +529 -107
- data/vendor/liburing/test/across-fork.c +7 -6
- data/vendor/liburing/test/{b19062a56726-test.c → b19062a56726.c} +3 -2
- data/vendor/liburing/test/{b5837bd5311d-test.c → b5837bd5311d.c} +10 -9
- data/vendor/liburing/test/buf-ring.c +420 -0
- data/vendor/liburing/test/{ce593a6c480a-test.c → ce593a6c480a.c} +15 -12
- data/vendor/liburing/test/connect.c +8 -7
- data/vendor/liburing/test/cq-full.c +5 -4
- data/vendor/liburing/test/cq-overflow.c +242 -12
- data/vendor/liburing/test/cq-peek-batch.c +5 -4
- data/vendor/liburing/test/cq-ready.c +5 -4
- data/vendor/liburing/test/cq-size.c +5 -4
- data/vendor/liburing/test/{d4ae271dfaae-test.c → d4ae271dfaae.c} +2 -2
- data/vendor/liburing/test/{d77a67ed5f27-test.c → d77a67ed5f27.c} +6 -6
- data/vendor/liburing/test/defer-taskrun.c +336 -0
- data/vendor/liburing/test/defer.c +26 -14
- data/vendor/liburing/test/double-poll-crash.c +15 -5
- data/vendor/liburing/test/drop-submit.c +5 -3
- data/vendor/liburing/test/{eeed8b54e0df-test.c → eeed8b54e0df.c} +7 -6
- data/vendor/liburing/test/empty-eownerdead.c +4 -4
- data/vendor/liburing/test/eventfd-disable.c +48 -20
- data/vendor/liburing/test/eventfd-reg.c +10 -9
- data/vendor/liburing/test/eventfd-ring.c +13 -12
- data/vendor/liburing/test/eventfd.c +13 -12
- data/vendor/liburing/test/exit-no-cleanup.c +1 -1
- data/vendor/liburing/test/fadvise.c +3 -3
- data/vendor/liburing/test/fallocate.c +16 -9
- data/vendor/liburing/test/{fc2a85cb02ef-test.c → fc2a85cb02ef.c} +4 -3
- data/vendor/liburing/test/fd-pass.c +187 -0
- data/vendor/liburing/test/file-register.c +302 -36
- data/vendor/liburing/test/file-update.c +62 -4
- data/vendor/liburing/test/file-verify.c +6 -2
- data/vendor/liburing/test/files-exit-hang-poll.c +11 -25
- data/vendor/liburing/test/files-exit-hang-timeout.c +13 -10
- data/vendor/liburing/test/fixed-buf-iter.c +115 -0
- data/vendor/liburing/test/fixed-link.c +10 -10
- data/vendor/liburing/test/fixed-reuse.c +160 -0
- data/vendor/liburing/test/fpos.c +6 -3
- data/vendor/liburing/test/fsync.c +3 -3
- data/vendor/liburing/test/hardlink.c +10 -6
- data/vendor/liburing/test/helpers.c +137 -4
- data/vendor/liburing/test/helpers.h +27 -0
- data/vendor/liburing/test/io-cancel.c +16 -11
- data/vendor/liburing/test/io_uring_enter.c +46 -81
- data/vendor/liburing/test/io_uring_passthrough.c +451 -0
- data/vendor/liburing/test/io_uring_register.c +59 -229
- data/vendor/liburing/test/io_uring_setup.c +24 -29
- data/vendor/liburing/test/iopoll-leak.c +85 -0
- data/vendor/liburing/test/iopoll.c +16 -9
- data/vendor/liburing/test/lfs-openat-write.c +3 -1
- data/vendor/liburing/test/link-timeout.c +4 -3
- data/vendor/liburing/test/link.c +8 -7
- data/vendor/liburing/test/madvise.c +2 -2
- data/vendor/liburing/test/mkdir.c +9 -5
- data/vendor/liburing/test/msg-ring.c +46 -20
- data/vendor/liburing/test/multicqes_drain.c +51 -12
- data/vendor/liburing/test/nolibc.c +60 -0
- data/vendor/liburing/test/nop.c +78 -16
- data/vendor/liburing/test/nvme.h +168 -0
- data/vendor/liburing/test/open-direct-link.c +188 -0
- data/vendor/liburing/test/open-direct-pick.c +180 -0
- data/vendor/liburing/test/openat2.c +3 -3
- data/vendor/liburing/test/poll-cancel-all.c +472 -0
- data/vendor/liburing/test/poll-link.c +9 -18
- data/vendor/liburing/test/poll-mshot-overflow.c +162 -0
- data/vendor/liburing/test/poll-mshot-update.c +83 -33
- data/vendor/liburing/test/pollfree.c +2 -2
- data/vendor/liburing/test/read-before-exit.c +112 -0
- data/vendor/liburing/test/read-write.c +83 -1
- data/vendor/liburing/test/recv-msgall-stream.c +398 -0
- data/vendor/liburing/test/recv-msgall.c +265 -0
- data/vendor/liburing/test/recv-multishot.c +505 -0
- data/vendor/liburing/test/rename.c +2 -5
- data/vendor/liburing/test/ring-leak.c +97 -0
- data/vendor/liburing/test/ringbuf-read.c +200 -0
- data/vendor/liburing/test/rsrc_tags.c +25 -13
- data/vendor/liburing/test/runtests-quiet.sh +11 -0
- data/vendor/liburing/test/runtests.sh +18 -20
- data/vendor/liburing/test/rw_merge_test.c +3 -2
- data/vendor/liburing/test/send-zerocopy.c +684 -0
- data/vendor/liburing/test/send_recv.c +49 -2
- data/vendor/liburing/test/send_recvmsg.c +165 -55
- data/vendor/liburing/test/shutdown.c +3 -4
- data/vendor/liburing/test/sigfd-deadlock.c +22 -8
- data/vendor/liburing/test/single-issuer.c +171 -0
- data/vendor/liburing/test/socket-rw-eagain.c +2 -12
- data/vendor/liburing/test/socket-rw-offset.c +2 -11
- data/vendor/liburing/test/socket-rw.c +2 -11
- data/vendor/liburing/test/socket.c +409 -0
- data/vendor/liburing/test/sq-poll-dup.c +1 -1
- data/vendor/liburing/test/sq-poll-share.c +1 -1
- data/vendor/liburing/test/statx.c +2 -2
- data/vendor/liburing/test/submit-and-wait.c +108 -0
- data/vendor/liburing/test/submit-link-fail.c +5 -3
- data/vendor/liburing/test/submit-reuse.c +0 -2
- data/vendor/liburing/test/sync-cancel.c +235 -0
- data/vendor/liburing/test/test.h +35 -0
- data/vendor/liburing/test/timeout-overflow.c +11 -11
- data/vendor/liburing/test/timeout.c +7 -7
- data/vendor/liburing/test/tty-write-dpoll.c +60 -0
- data/vendor/liburing/test/unlink.c +1 -1
- data/vendor/liburing/test/xattr.c +425 -0
- metadata +148 -26
- data/Gemfile.lock +0 -82
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include <fcntl.h>
|
|
12
12
|
|
|
13
13
|
#include "liburing.h"
|
|
14
|
+
#include "helpers.h"
|
|
14
15
|
|
|
15
16
|
static int queue_n_nops(struct io_uring *ring, int n)
|
|
16
17
|
{
|
|
@@ -49,13 +50,13 @@ int main(int argc, char *argv[])
|
|
|
49
50
|
int i, ret;
|
|
50
51
|
|
|
51
52
|
if (argc > 1)
|
|
52
|
-
return
|
|
53
|
+
return T_EXIT_SKIP;
|
|
53
54
|
|
|
54
55
|
memset(&p, 0, sizeof(p));
|
|
55
56
|
ret = io_uring_queue_init_params(4, &ring, &p);
|
|
56
57
|
if (ret) {
|
|
57
58
|
printf("ring setup failed\n");
|
|
58
|
-
return
|
|
59
|
+
return T_EXIT_FAIL;
|
|
59
60
|
|
|
60
61
|
}
|
|
61
62
|
|
|
@@ -89,8 +90,8 @@ int main(int argc, char *argv[])
|
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
io_uring_queue_exit(&ring);
|
|
92
|
-
return
|
|
93
|
+
return T_EXIT_PASS;
|
|
93
94
|
err:
|
|
94
95
|
io_uring_queue_exit(&ring);
|
|
95
|
-
return
|
|
96
|
+
return T_EXIT_FAIL;
|
|
96
97
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
#include <stdlib.h>
|
|
10
10
|
#include <string.h>
|
|
11
11
|
#include <fcntl.h>
|
|
12
|
+
#include <assert.h>
|
|
12
13
|
|
|
13
14
|
#include "helpers.h"
|
|
14
15
|
#include "liburing.h"
|
|
@@ -21,6 +22,32 @@ static struct iovec *vecs;
|
|
|
21
22
|
|
|
22
23
|
#define ENTRIES 8
|
|
23
24
|
|
|
25
|
+
/*
|
|
26
|
+
* io_uring has rare cases where CQEs are lost.
|
|
27
|
+
* This happens when there is no space in the CQ ring, and also there is no
|
|
28
|
+
* GFP_ATOMIC memory available. In reality this probably means that the process
|
|
29
|
+
* is about to be killed as many other things might start failing, but we still
|
|
30
|
+
* want to test that liburing and the kernel deal with this properly. The fault
|
|
31
|
+
* injection framework allows us to test this scenario. Unfortunately this
|
|
32
|
+
* requires some system wide changes and so we do not enable this by default.
|
|
33
|
+
* The tests in this file should work in both cases (where overflows are queued
|
|
34
|
+
* and where they are dropped) on recent kernels.
|
|
35
|
+
*
|
|
36
|
+
* In order to test dropped CQEs you should enable fault injection in the kernel
|
|
37
|
+
* config:
|
|
38
|
+
*
|
|
39
|
+
* CONFIG_FAULT_INJECTION=y
|
|
40
|
+
* CONFIG_FAILSLAB=y
|
|
41
|
+
* CONFIG_FAULT_INJECTION_DEBUG_FS=y
|
|
42
|
+
*
|
|
43
|
+
* and then run the test as follows:
|
|
44
|
+
* echo Y > /sys/kernel/debug/failslab/task-filter
|
|
45
|
+
* echo 100 > /sys/kernel/debug/failslab/probability
|
|
46
|
+
* echo 0 > /sys/kernel/debug/failslab/verbose
|
|
47
|
+
* echo 100000 > /sys/kernel/debug/failslab/times
|
|
48
|
+
* bash -c "echo 1 > /proc/self/make-it-fail && exec ./cq-overflow.t"
|
|
49
|
+
*/
|
|
50
|
+
|
|
24
51
|
static int test_io(const char *file, unsigned long usecs, unsigned *drops, int fault)
|
|
25
52
|
{
|
|
26
53
|
struct io_uring_sqe *sqe;
|
|
@@ -29,18 +56,20 @@ static int test_io(const char *file, unsigned long usecs, unsigned *drops, int f
|
|
|
29
56
|
unsigned reaped, total;
|
|
30
57
|
struct io_uring ring;
|
|
31
58
|
int nodrop, i, fd, ret;
|
|
59
|
+
bool cqe_dropped = false;
|
|
32
60
|
|
|
33
61
|
fd = open(file, O_RDONLY | O_DIRECT);
|
|
34
62
|
if (fd < 0) {
|
|
35
63
|
perror("file open");
|
|
36
|
-
|
|
64
|
+
return 1;
|
|
37
65
|
}
|
|
38
66
|
|
|
39
67
|
memset(&p, 0, sizeof(p));
|
|
40
68
|
ret = io_uring_queue_init_params(ENTRIES, &ring, &p);
|
|
41
69
|
if (ret) {
|
|
70
|
+
close(fd);
|
|
42
71
|
fprintf(stderr, "ring create failed: %d\n", ret);
|
|
43
|
-
|
|
72
|
+
return 1;
|
|
44
73
|
}
|
|
45
74
|
nodrop = 0;
|
|
46
75
|
if (p.features & IORING_FEAT_NODROP)
|
|
@@ -103,8 +132,8 @@ static int test_io(const char *file, unsigned long usecs, unsigned *drops, int f
|
|
|
103
132
|
reap_it:
|
|
104
133
|
reaped = 0;
|
|
105
134
|
do {
|
|
106
|
-
if (nodrop) {
|
|
107
|
-
/* nodrop should never lose events */
|
|
135
|
+
if (nodrop && !cqe_dropped) {
|
|
136
|
+
/* nodrop should never lose events unless cqe_dropped */
|
|
108
137
|
if (reaped == total)
|
|
109
138
|
break;
|
|
110
139
|
} else {
|
|
@@ -112,7 +141,10 @@ reap_it:
|
|
|
112
141
|
break;
|
|
113
142
|
}
|
|
114
143
|
ret = io_uring_wait_cqe(&ring, &cqe);
|
|
115
|
-
if (ret) {
|
|
144
|
+
if (nodrop && ret == -EBADR) {
|
|
145
|
+
cqe_dropped = true;
|
|
146
|
+
continue;
|
|
147
|
+
} else if (ret) {
|
|
116
148
|
fprintf(stderr, "wait_cqe=%d\n", ret);
|
|
117
149
|
goto err;
|
|
118
150
|
}
|
|
@@ -132,7 +164,7 @@ reap_it:
|
|
|
132
164
|
goto err;
|
|
133
165
|
}
|
|
134
166
|
|
|
135
|
-
if (!nodrop) {
|
|
167
|
+
if (!nodrop || cqe_dropped) {
|
|
136
168
|
*drops = *ring.cq.koverflow;
|
|
137
169
|
} else if (*ring.cq.koverflow) {
|
|
138
170
|
fprintf(stderr, "Found %u overflows\n", *ring.cq.koverflow);
|
|
@@ -153,18 +185,29 @@ static int reap_events(struct io_uring *ring, unsigned nr_events, int do_wait)
|
|
|
153
185
|
{
|
|
154
186
|
struct io_uring_cqe *cqe;
|
|
155
187
|
int i, ret = 0, seq = 0;
|
|
188
|
+
unsigned int start_overflow = *ring->cq.koverflow;
|
|
189
|
+
bool dropped = false;
|
|
156
190
|
|
|
157
191
|
for (i = 0; i < nr_events; i++) {
|
|
158
192
|
if (do_wait)
|
|
159
193
|
ret = io_uring_wait_cqe(ring, &cqe);
|
|
160
194
|
else
|
|
161
195
|
ret = io_uring_peek_cqe(ring, &cqe);
|
|
162
|
-
if (ret) {
|
|
196
|
+
if (do_wait && ret == -EBADR) {
|
|
197
|
+
unsigned int this_drop = *ring->cq.koverflow -
|
|
198
|
+
start_overflow;
|
|
199
|
+
|
|
200
|
+
dropped = true;
|
|
201
|
+
start_overflow = *ring->cq.koverflow;
|
|
202
|
+
assert(this_drop > 0);
|
|
203
|
+
i += (this_drop - 1);
|
|
204
|
+
continue;
|
|
205
|
+
} else if (ret) {
|
|
163
206
|
if (ret != -EAGAIN)
|
|
164
207
|
fprintf(stderr, "cqe peek failed: %d\n", ret);
|
|
165
208
|
break;
|
|
166
209
|
}
|
|
167
|
-
if (cqe->user_data != seq) {
|
|
210
|
+
if (!dropped && cqe->user_data != seq) {
|
|
168
211
|
fprintf(stderr, "cqe sequence out-of-order\n");
|
|
169
212
|
fprintf(stderr, "got %d, wanted %d\n", (int) cqe->user_data,
|
|
170
213
|
seq);
|
|
@@ -241,19 +284,206 @@ err:
|
|
|
241
284
|
return 1;
|
|
242
285
|
}
|
|
243
286
|
|
|
287
|
+
|
|
288
|
+
static void submit_one_nop(struct io_uring *ring, int ud)
|
|
289
|
+
{
|
|
290
|
+
struct io_uring_sqe *sqe;
|
|
291
|
+
int ret;
|
|
292
|
+
|
|
293
|
+
sqe = io_uring_get_sqe(ring);
|
|
294
|
+
assert(sqe);
|
|
295
|
+
io_uring_prep_nop(sqe);
|
|
296
|
+
sqe->user_data = ud;
|
|
297
|
+
ret = io_uring_submit(ring);
|
|
298
|
+
assert(ret == 1);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/*
|
|
302
|
+
* Create an overflow condition and ensure that SQEs are still processed
|
|
303
|
+
*/
|
|
304
|
+
static int test_overflow_handling(bool batch, int cqe_multiple, bool poll,
|
|
305
|
+
bool defer)
|
|
306
|
+
{
|
|
307
|
+
struct io_uring ring;
|
|
308
|
+
struct io_uring_params p;
|
|
309
|
+
int ret, i, j, ud, cqe_count;
|
|
310
|
+
unsigned int count;
|
|
311
|
+
int const N = 8;
|
|
312
|
+
int const LOOPS = 128;
|
|
313
|
+
int const QUEUE_LENGTH = 1024;
|
|
314
|
+
int completions[N];
|
|
315
|
+
int queue[QUEUE_LENGTH];
|
|
316
|
+
int queued = 0;
|
|
317
|
+
int outstanding = 0;
|
|
318
|
+
bool cqe_dropped = false;
|
|
319
|
+
|
|
320
|
+
memset(&completions, 0, sizeof(int) * N);
|
|
321
|
+
memset(&p, 0, sizeof(p));
|
|
322
|
+
p.cq_entries = 2 * cqe_multiple;
|
|
323
|
+
p.flags |= IORING_SETUP_CQSIZE;
|
|
324
|
+
|
|
325
|
+
if (poll)
|
|
326
|
+
p.flags |= IORING_SETUP_IOPOLL;
|
|
327
|
+
|
|
328
|
+
if (defer)
|
|
329
|
+
p.flags |= IORING_SETUP_SINGLE_ISSUER |
|
|
330
|
+
IORING_SETUP_DEFER_TASKRUN;
|
|
331
|
+
|
|
332
|
+
ret = io_uring_queue_init_params(2, &ring, &p);
|
|
333
|
+
if (ret) {
|
|
334
|
+
fprintf(stderr, "io_uring_queue_init failed %d\n", ret);
|
|
335
|
+
return 1;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
assert(p.cq_entries < N);
|
|
339
|
+
/* submit N SQEs, some should overflow */
|
|
340
|
+
for (i = 0; i < N; i++) {
|
|
341
|
+
submit_one_nop(&ring, i);
|
|
342
|
+
outstanding++;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
for (i = 0; i < LOOPS; i++) {
|
|
346
|
+
struct io_uring_cqe *cqes[N];
|
|
347
|
+
|
|
348
|
+
if (io_uring_cq_has_overflow(&ring)) {
|
|
349
|
+
/*
|
|
350
|
+
* Flush any overflowed CQEs and process those. Actively
|
|
351
|
+
* flush these to make sure CQEs arrive in vague order
|
|
352
|
+
* of being sent.
|
|
353
|
+
*/
|
|
354
|
+
ret = io_uring_get_events(&ring);
|
|
355
|
+
if (ret != 0) {
|
|
356
|
+
fprintf(stderr,
|
|
357
|
+
"io_uring_get_events returned %d\n",
|
|
358
|
+
ret);
|
|
359
|
+
goto err;
|
|
360
|
+
}
|
|
361
|
+
} else if (!cqe_dropped) {
|
|
362
|
+
for (j = 0; j < queued; j++) {
|
|
363
|
+
submit_one_nop(&ring, queue[j]);
|
|
364
|
+
outstanding++;
|
|
365
|
+
}
|
|
366
|
+
queued = 0;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/* We have lost some random cqes, stop if no remaining. */
|
|
370
|
+
if (cqe_dropped && outstanding == *ring.cq.koverflow)
|
|
371
|
+
break;
|
|
372
|
+
|
|
373
|
+
ret = io_uring_wait_cqe(&ring, &cqes[0]);
|
|
374
|
+
if (ret == -EBADR) {
|
|
375
|
+
cqe_dropped = true;
|
|
376
|
+
fprintf(stderr, "CQE dropped\n");
|
|
377
|
+
continue;
|
|
378
|
+
} else if (ret != 0) {
|
|
379
|
+
fprintf(stderr, "io_uring_wait_cqes failed %d\n", ret);
|
|
380
|
+
goto err;
|
|
381
|
+
}
|
|
382
|
+
cqe_count = 1;
|
|
383
|
+
if (batch) {
|
|
384
|
+
ret = io_uring_peek_batch_cqe(&ring, &cqes[0], 2);
|
|
385
|
+
if (ret < 0) {
|
|
386
|
+
fprintf(stderr,
|
|
387
|
+
"io_uring_peek_batch_cqe failed %d\n",
|
|
388
|
+
ret);
|
|
389
|
+
goto err;
|
|
390
|
+
}
|
|
391
|
+
cqe_count = ret;
|
|
392
|
+
}
|
|
393
|
+
for (j = 0; j < cqe_count; j++) {
|
|
394
|
+
assert(cqes[j]->user_data < N);
|
|
395
|
+
ud = cqes[j]->user_data;
|
|
396
|
+
completions[ud]++;
|
|
397
|
+
assert(queued < QUEUE_LENGTH);
|
|
398
|
+
queue[queued++] = (int)ud;
|
|
399
|
+
}
|
|
400
|
+
io_uring_cq_advance(&ring, cqe_count);
|
|
401
|
+
outstanding -= cqe_count;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/* See if there were any drops by flushing the CQ ring *and* overflow */
|
|
405
|
+
do {
|
|
406
|
+
struct io_uring_cqe *cqe;
|
|
407
|
+
|
|
408
|
+
ret = io_uring_get_events(&ring);
|
|
409
|
+
if (ret < 0) {
|
|
410
|
+
if (ret == -EBADR) {
|
|
411
|
+
fprintf(stderr, "CQE dropped\n");
|
|
412
|
+
cqe_dropped = true;
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
goto err;
|
|
416
|
+
}
|
|
417
|
+
if (outstanding && !io_uring_cq_ready(&ring))
|
|
418
|
+
ret = io_uring_wait_cqe_timeout(&ring, &cqe, NULL);
|
|
419
|
+
|
|
420
|
+
if (ret && ret != -ETIME) {
|
|
421
|
+
if (ret == -EBADR) {
|
|
422
|
+
fprintf(stderr, "CQE dropped\n");
|
|
423
|
+
cqe_dropped = true;
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
fprintf(stderr, "wait_cqe_timeout = %d\n", ret);
|
|
427
|
+
goto err;
|
|
428
|
+
}
|
|
429
|
+
count = io_uring_cq_ready(&ring);
|
|
430
|
+
io_uring_cq_advance(&ring, count);
|
|
431
|
+
outstanding -= count;
|
|
432
|
+
} while (count);
|
|
433
|
+
|
|
434
|
+
io_uring_queue_exit(&ring);
|
|
435
|
+
|
|
436
|
+
/* Make sure that completions come back in the same order they were
|
|
437
|
+
* sent. If they come back unfairly then this will concentrate on a
|
|
438
|
+
* couple of indices.
|
|
439
|
+
*/
|
|
440
|
+
for (i = 1; !cqe_dropped && i < N; i++) {
|
|
441
|
+
if (abs(completions[i] - completions[i - 1]) > 1) {
|
|
442
|
+
fprintf(stderr, "bad completion size %d %d\n",
|
|
443
|
+
completions[i], completions[i - 1]);
|
|
444
|
+
goto err;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return 0;
|
|
448
|
+
err:
|
|
449
|
+
io_uring_queue_exit(&ring);
|
|
450
|
+
return 1;
|
|
451
|
+
}
|
|
452
|
+
|
|
244
453
|
int main(int argc, char *argv[])
|
|
245
454
|
{
|
|
246
455
|
const char *fname = ".cq-overflow";
|
|
247
456
|
unsigned iters, drops;
|
|
248
457
|
unsigned long usecs;
|
|
249
458
|
int ret;
|
|
459
|
+
int i;
|
|
460
|
+
bool can_defer;
|
|
250
461
|
|
|
251
462
|
if (argc > 1)
|
|
252
|
-
return
|
|
463
|
+
return T_EXIT_SKIP;
|
|
464
|
+
|
|
465
|
+
can_defer = t_probe_defer_taskrun();
|
|
466
|
+
for (i = 0; i < 16; i++) {
|
|
467
|
+
bool batch = i & 1;
|
|
468
|
+
int mult = (i & 2) ? 1 : 2;
|
|
469
|
+
bool poll = i & 4;
|
|
470
|
+
bool defer = i & 8;
|
|
471
|
+
|
|
472
|
+
if (defer && !can_defer)
|
|
473
|
+
continue;
|
|
474
|
+
|
|
475
|
+
ret = test_overflow_handling(batch, mult, poll, defer);
|
|
476
|
+
if (ret) {
|
|
477
|
+
fprintf(stderr, "test_overflow_handling("
|
|
478
|
+
"batch=%d, mult=%d, poll=%d, defer=%d) failed\n",
|
|
479
|
+
batch, mult, poll, defer);
|
|
480
|
+
goto err;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
253
483
|
|
|
254
484
|
ret = test_overflow();
|
|
255
485
|
if (ret) {
|
|
256
|
-
|
|
486
|
+
fprintf(stderr, "test_overflow failed\n");
|
|
257
487
|
return ret;
|
|
258
488
|
}
|
|
259
489
|
|
|
@@ -287,8 +517,8 @@ int main(int argc, char *argv[])
|
|
|
287
517
|
}
|
|
288
518
|
|
|
289
519
|
unlink(fname);
|
|
290
|
-
return
|
|
520
|
+
return T_EXIT_PASS;
|
|
291
521
|
err:
|
|
292
522
|
unlink(fname);
|
|
293
|
-
return
|
|
523
|
+
return T_EXIT_FAIL;
|
|
294
524
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include <fcntl.h>
|
|
12
12
|
|
|
13
13
|
#include "liburing.h"
|
|
14
|
+
#include "helpers.h"
|
|
14
15
|
|
|
15
16
|
static int queue_n_nops(struct io_uring *ring, int n, int offset)
|
|
16
17
|
{
|
|
@@ -58,12 +59,12 @@ int main(int argc, char *argv[])
|
|
|
58
59
|
unsigned got;
|
|
59
60
|
|
|
60
61
|
if (argc > 1)
|
|
61
|
-
return
|
|
62
|
+
return T_EXIT_SKIP;
|
|
62
63
|
|
|
63
64
|
ret = io_uring_queue_init(4, &ring, 0);
|
|
64
65
|
if (ret) {
|
|
65
66
|
printf("ring setup failed\n");
|
|
66
|
-
return
|
|
67
|
+
return T_EXIT_FAIL;
|
|
67
68
|
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -95,8 +96,8 @@ int main(int argc, char *argv[])
|
|
|
95
96
|
|
|
96
97
|
io_uring_cq_advance(&ring, 8);
|
|
97
98
|
io_uring_queue_exit(&ring);
|
|
98
|
-
return
|
|
99
|
+
return T_EXIT_PASS;
|
|
99
100
|
err:
|
|
100
101
|
io_uring_queue_exit(&ring);
|
|
101
|
-
return
|
|
102
|
+
return T_EXIT_FAIL;
|
|
102
103
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include <fcntl.h>
|
|
12
12
|
|
|
13
13
|
#include "liburing.h"
|
|
14
|
+
#include "helpers.h"
|
|
14
15
|
|
|
15
16
|
static int queue_n_nops(struct io_uring *ring, int n)
|
|
16
17
|
{
|
|
@@ -56,12 +57,12 @@ int main(int argc, char *argv[])
|
|
|
56
57
|
unsigned ready;
|
|
57
58
|
|
|
58
59
|
if (argc > 1)
|
|
59
|
-
return
|
|
60
|
+
return T_EXIT_SKIP;
|
|
60
61
|
|
|
61
62
|
ret = io_uring_queue_init(4, &ring, 0);
|
|
62
63
|
if (ret) {
|
|
63
64
|
printf("ring setup failed\n");
|
|
64
|
-
return
|
|
65
|
+
return T_EXIT_FAIL;
|
|
65
66
|
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -87,8 +88,8 @@ int main(int argc, char *argv[])
|
|
|
87
88
|
CHECK_READY(&ring, 0);
|
|
88
89
|
|
|
89
90
|
io_uring_queue_exit(&ring);
|
|
90
|
-
return
|
|
91
|
+
return T_EXIT_PASS;
|
|
91
92
|
err:
|
|
92
93
|
io_uring_queue_exit(&ring);
|
|
93
|
-
return
|
|
94
|
+
return T_EXIT_FAIL;
|
|
94
95
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#include <fcntl.h>
|
|
11
11
|
|
|
12
12
|
#include "liburing.h"
|
|
13
|
+
#include "helpers.h"
|
|
13
14
|
|
|
14
15
|
int main(int argc, char *argv[])
|
|
15
16
|
{
|
|
@@ -18,7 +19,7 @@ int main(int argc, char *argv[])
|
|
|
18
19
|
int ret;
|
|
19
20
|
|
|
20
21
|
if (argc > 1)
|
|
21
|
-
return
|
|
22
|
+
return T_EXIT_SKIP;
|
|
22
23
|
|
|
23
24
|
memset(&p, 0, sizeof(p));
|
|
24
25
|
p.flags = IORING_SETUP_CQSIZE;
|
|
@@ -31,7 +32,7 @@ int main(int argc, char *argv[])
|
|
|
31
32
|
goto done;
|
|
32
33
|
}
|
|
33
34
|
printf("ring setup failed\n");
|
|
34
|
-
return
|
|
35
|
+
return T_EXIT_FAIL;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
if (p.cq_entries < 64) {
|
|
@@ -58,7 +59,7 @@ int main(int argc, char *argv[])
|
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
done:
|
|
61
|
-
return
|
|
62
|
+
return T_EXIT_PASS;
|
|
62
63
|
err:
|
|
63
|
-
return
|
|
64
|
+
return T_EXIT_FAIL;
|
|
64
65
|
}
|
|
@@ -31,9 +31,9 @@ int main(int argc, char *argv[])
|
|
|
31
31
|
p.flags = IORING_SETUP_SQPOLL;
|
|
32
32
|
ret = t_create_ring_params(4, &ring, &p);
|
|
33
33
|
if (ret == T_SETUP_SKIP)
|
|
34
|
-
return
|
|
34
|
+
return T_EXIT_SKIP;
|
|
35
35
|
else if (ret < 0)
|
|
36
|
-
return
|
|
36
|
+
return T_EXIT_FAIL;
|
|
37
37
|
|
|
38
38
|
if (argc > 1) {
|
|
39
39
|
fname = argv[1];
|
|
@@ -22,7 +22,7 @@ int main(int argc, char *argv[])
|
|
|
22
22
|
int ret, data;
|
|
23
23
|
|
|
24
24
|
if (argc > 1)
|
|
25
|
-
return
|
|
25
|
+
return T_EXIT_SKIP;
|
|
26
26
|
|
|
27
27
|
signal(SIGALRM, sig_alrm);
|
|
28
28
|
|
|
@@ -31,9 +31,9 @@ int main(int argc, char *argv[])
|
|
|
31
31
|
p.flags = IORING_SETUP_SQPOLL;
|
|
32
32
|
ret = t_create_ring_params(4, &ring, &p);
|
|
33
33
|
if (ret == T_SETUP_SKIP)
|
|
34
|
-
return
|
|
34
|
+
return T_EXIT_SKIP;
|
|
35
35
|
else if (ret < 0)
|
|
36
|
-
return
|
|
36
|
+
return T_EXIT_FAIL;
|
|
37
37
|
|
|
38
38
|
/* make sure sq thread is sleeping at this point */
|
|
39
39
|
usleep(150000);
|
|
@@ -42,7 +42,7 @@ int main(int argc, char *argv[])
|
|
|
42
42
|
sqe = io_uring_get_sqe(&ring);
|
|
43
43
|
if (!sqe) {
|
|
44
44
|
fprintf(stderr, "sqe get failed\n");
|
|
45
|
-
return
|
|
45
|
+
return T_EXIT_FAIL;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
io_uring_prep_nop(sqe);
|
|
@@ -58,8 +58,8 @@ int main(int argc, char *argv[])
|
|
|
58
58
|
data = (unsigned long) io_uring_cqe_get_data(cqe);
|
|
59
59
|
if (data != 42) {
|
|
60
60
|
fprintf(stderr, "invalid data: %d\n", data);
|
|
61
|
-
return
|
|
61
|
+
return T_EXIT_FAIL;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
return
|
|
64
|
+
return T_EXIT_PASS;
|
|
65
65
|
}
|