diff --git a/cfg/tarantool_box_cfg.c b/cfg/tarantool_box_cfg.c index 2924909e017906eded4ee0697636f28b56212ef9..9ac4a967e7c273ee12020ff76822b4b8b010cf43 100644 --- a/cfg/tarantool_box_cfg.c +++ b/cfg/tarantool_box_cfg.c @@ -112,6 +112,13 @@ fill_default_tarantool_cfg(tarantool_cfg *c) { return 0; } +void +swap_tarantool_cfg(struct tarantool_cfg *c1, struct tarantool_cfg *c2) { + struct tarantool_cfg tmpcfg = *c1; + *c1 = *c2; + *c2 = tmpcfg; +} + static int acceptDefault_name__namespace(tarantool_cfg_namespace *c) { c->enabled = -1; diff --git a/cfg/tarantool_box_cfg.h b/cfg/tarantool_box_cfg.h index d1d777b2fe4cf3138ba63c1615874805cb3bd5c3..44a9c4a1b27f16485073d5a9eb7534deb31dfb5b 100644 --- a/cfg/tarantool_box_cfg.h +++ b/cfg/tarantool_box_cfg.h @@ -174,6 +174,8 @@ void init_tarantool_cfg(tarantool_cfg *c); int fill_default_tarantool_cfg(tarantool_cfg *c); +void swap_tarantool_cfg(struct tarantool_cfg *c1, struct tarantool_cfg *c2); + void parse_cfg_file_tarantool_cfg(tarantool_cfg *c, FILE *fh, int check_rdonly, int *n_accepted, int *n_skipped); void parse_cfg_buffer_tarantool_cfg(tarantool_cfg *c, char *buffer, int check_rdonly, int *n_accepted, int *n_skipped); diff --git a/cfg/tarantool_feeder_cfg.c b/cfg/tarantool_feeder_cfg.c index c1119f2157fda5eb9ddde5cdb6d0a1b2fb917430..3f5fb82f1f76f89b82bb06505d7c8671b3a8e58f 100644 --- a/cfg/tarantool_feeder_cfg.c +++ b/cfg/tarantool_feeder_cfg.c @@ -74,6 +74,13 @@ fill_default_tarantool_cfg(tarantool_cfg *c) { return 0; } +void +swap_tarantool_cfg(struct tarantool_cfg *c1, struct tarantool_cfg *c2) { + struct tarantool_cfg tmpcfg = *c1; + *c1 = *c2; + *c2 = tmpcfg; +} + static NameAtom _name__username[] = { { "username", -1, NULL } }; diff --git a/cfg/tarantool_feeder_cfg.h b/cfg/tarantool_feeder_cfg.h index 8384d02ded333f1a3e3d2963956fe4170c14359d..8296b42de4bee483f5a763bd6da5c467548846d2 100644 --- a/cfg/tarantool_feeder_cfg.h +++ b/cfg/tarantool_feeder_cfg.h @@ -90,6 +90,8 @@ void init_tarantool_cfg(tarantool_cfg *c); int fill_default_tarantool_cfg(tarantool_cfg *c); +void swap_tarantool_cfg(struct tarantool_cfg *c1, struct tarantool_cfg *c2); + void parse_cfg_file_tarantool_cfg(tarantool_cfg *c, FILE *fh, int check_rdonly, int *n_accepted, int *n_skipped); void parse_cfg_buffer_tarantool_cfg(tarantool_cfg *c, char *buffer, int check_rdonly, int *n_accepted, int *n_skipped); diff --git a/core/fiber.m b/core/fiber.m index d0c81026cd3297acc3179505cbe2507f873621b2..682f68079cffe8aabe8576a7dc785ec314d1a633 100644 --- a/core/fiber.m +++ b/core/fiber.m @@ -56,7 +56,7 @@ #include <pickle.h> #include "diagnostics.h" -@implementation tnt_FiberException +@implementation tnt_FiberCancelException @end static struct fiber sched; @@ -134,22 +134,23 @@ fiber_wakeup(struct fiber *f) ev_async_send(&f->async); } -/** Cancel the subject fiber. +/** Cancel the subject fiber. * * Note: this is not guaranteed to succeed, and requires a level - * of cooperation on behalf of the fiber. A fiber may opt to - * set FIBER_CANCELLABLE to false, and never test that it was cancelled. - * Such fiber we won't be ever to cancel, ever, and for such fiber - * this call will lead to an infinite wait. - * However, fiber_testcancel() is embedded to the rest of fiber_* API - * (@sa yield()), which makes most of the fibers that opt in, cancellable. + * of cooperation on behalf of the fiber. A fiber may opt to set + * FIBER_CANCELLABLE to false, and never test that it was + * cancelled. Such fiber we won't be ever to cancel, ever, and + * for such fiber this call will lead to an infinite wait. + * However, fiber_testcancel() is embedded to the rest of fiber_* + * API (@sa yield()), which makes most of the fibers that opt in, + * cancellable. * - * Currently cancellation can only be synchronous: this call returns - * only when the subject fiber has terminated. + * Currently cancellation can only be synchronous: this call + * returns only when the subject fiber has terminated. * - * The fiber which is cancelled, has tnt_FiberException raised in it. - * For cancellation to work, this exception type should be re-raised - * whenever (if) it is caught. + * The fiber which is cancelled, has tnt_FiberCancelException + * raised in it. For cancellation to work, this exception type + * should be re-raised whenever (if) it is caught. */ void @@ -175,8 +176,9 @@ fiber_cancel(struct fiber *f) } -/** Test if this fiber is in a cancellable state and was indeed cancelled, - * and raise an exception (tnt_FiberException) if that's the case. +/** Test if this fiber is in a cancellable state and was indeed + * cancelled, and raise an exception (tnt_FiberCancelException) if + * that's the case. */ void @@ -188,11 +190,11 @@ fiber_testcancel(void) if (!(fiber->flags & FIBER_CANCEL)) return; - tnt_raise(tnt_FiberException, reason:"fiber_testcancel: fiber to be canceled"); + tnt_raise(tnt_FiberCancelException, reason:"fiber_testcancel"); } -/** Change the current cancellation state of a fiber. - * This is not a cancellation point. +/** Change the current cancellation state of a fiber. This is not + * a cancellation point. */ void fiber_setcancelstate(bool enable) @@ -274,7 +276,14 @@ wait_for(int events) if (!ev_is_active(io)) ev_io_start(io); - yield(); + @try { + yield(); + } + @catch (id o) + { + ev_io_stop(io); + @throw; + } } static void @@ -430,14 +439,13 @@ fiber_zombificate() static void fiber_loop(void *data __attribute__((unused))) { - while (42) { + while (true) { assert(fiber != NULL && fiber->f != NULL && fiber->fid != 0); @try { fiber->f(fiber->f_data); } - @catch (tnt_FiberException *e) { - say_info("fiber `%s': exception `tnt_FiberException': `%s'", - fiber->name, e->reason); + @catch (tnt_FiberCancelException *e) { + say_info("fiber `%s' has been cancelled", fiber->name); if (fiber->waiter != NULL) { fiber_call(fiber->waiter); @@ -463,8 +471,10 @@ fiber_loop(void *data __attribute__((unused))) } } -/** Set fiber name. -* @Param[in] name the new name of the fiber. Truncated to FIBER_NAME_MAXLEN. +/** Set fiber name. + * + * @param[in] name the new name of the fiber. Truncated to + * FIBER_NAME_MAXLEN. */ void @@ -676,24 +686,20 @@ fiber_bread(struct tbuf *buf, size_t at_least) ssize_t r; tbuf_ensure(buf, MAX(cfg.readahead, at_least)); - @try { - for (;;) { - wait_for(EV_READ); - r = read(fiber->fd, buf->data + buf->len, buf->size - buf->len); - if (r > 0) { - buf->len += r; - if (buf->len >= at_least) - break; - } else { - if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) - continue; + for (;;) { + wait_for(EV_READ); + r = read(fiber->fd, buf->data + buf->len, buf->size - buf->len); + if (r > 0) { + buf->len += r; + if (buf->len >= at_least) break; - } + } else { + if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) + continue; + break; } } - @finally { - unwait(EV_READ); - } + unwait(EV_READ); return r; } @@ -717,33 +723,29 @@ fiber_flush_output(void) struct iovec *iov = iovec(fiber->iov); size_t iov_cnt = fiber->iov_cnt; - @try { - while (iov_cnt > 0) { - wait_for(EV_WRITE); - bytes += r = writev(fiber->fd, iov, MIN(iov_cnt, IOV_MAX)); - if (r <= 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - continue; - else - break; - } + while (iov_cnt > 0) { + wait_for(EV_WRITE); + bytes += r = writev(fiber->fd, iov, MIN(iov_cnt, IOV_MAX)); + if (r <= 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + continue; + else + break; + } - while (iov_cnt > 0) { - if (iov->iov_len > r) { - iov->iov_base += r; - iov->iov_len -= r; - break; - } else { - r -= iov->iov_len; - iov++; - iov_cnt--; - } + while (iov_cnt > 0) { + if (iov->iov_len > r) { + iov->iov_base += r; + iov->iov_len -= r; + break; + } else { + r -= iov->iov_len; + iov++; + iov_cnt--; } } } - @finally { - unwait(EV_WRITE); - } + unwait(EV_WRITE); if (r < 0) { size_t rem = 0; @@ -772,22 +774,18 @@ fiber_read(void *buf, size_t count) if (count == 0) return 0; - @try { - while (count != done) { - wait_for(EV_READ); - - if ((r = read(fiber->fd, buf + done, count - done)) <= 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - continue; - else - break; - } - done += r; + while (count != done) { + wait_for(EV_READ); + + if ((r = read(fiber->fd, buf + done, count - done)) <= 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + continue; + else + break; } + done += r; } - @finally { - unwait(EV_READ); - } + unwait(EV_READ); return done; } @@ -805,21 +803,17 @@ fiber_write(const void *buf, size_t count) if (count == 0) return 0; - @try { - while (count != done) { - wait_for(EV_WRITE); - if ((r = write(fiber->fd, buf + done, count - done)) == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - continue; - else - break; - } - done += r; + while (count != done) { + wait_for(EV_WRITE); + if ((r = write(fiber->fd, buf + done, count - done)) == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + continue; + else + break; } + done += r; } - @finally { - unwait(EV_WRITE); - } + unwait(EV_WRITE); return done; } @@ -846,21 +840,17 @@ fiber_connect(struct sockaddr_in *addr) goto error; } - @try { - wait_for(EV_WRITE); - if (getsockopt(fiber->fd, SOL_SOCKET, SO_ERROR, &error, &error_size) < 0) - goto error; + wait_for(EV_WRITE); + if (getsockopt(fiber->fd, SOL_SOCKET, SO_ERROR, &error, &error_size) < 0) + goto error; - assert(error_size == sizeof(error)); + assert(error_size == sizeof(error)); - if (error != 0) { - errno = error; - goto error; - } - } - @finally { - unwait(EV_WRITE); + if (error != 0) { + errno = error; + goto error; } + unwait(EV_WRITE); return fiber->fd; @@ -1153,42 +1143,38 @@ tcp_server_handler(void *data) if (server->on_bind != NULL) server->on_bind(server->data); - @try { - while (1) { - wait_for(EV_READ); - - while ((fd = accept(fiber->fd, NULL, NULL)) > 0) { - if (set_nonblock(fd) == -1) { - say_error("can't set nonblock"); - close(fd); - continue; - } - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, - &one, sizeof(one)) == -1) { - say_syserror("setsockopt failed"); - /* Do nothing, not a fatal error. */ - } - - snprintf(name, sizeof(name), "%i/handler", server->port); - h = fiber_create(name, fd, -1, server->handler, data); - if (h == NULL) { - say_error("can't create handler fiber, dropping client connection"); - close(fd); - continue; - } - - h->has_peer = true; - fiber_call(h); - } - if (fd < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { - say_syserror("accept"); - continue; - } + while (1) { + wait_for(EV_READ); + + while ((fd = accept(fiber->fd, NULL, NULL)) > 0) { + if (set_nonblock(fd) == -1) { + say_error("can't set nonblock"); + close(fd); + continue; + } + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, + &one, sizeof(one)) == -1) { + say_syserror("setsockopt failed"); + /* Do nothing, not a fatal error. */ + } + + snprintf(name, sizeof(name), "%i/handler", server->port); + h = fiber_create(name, fd, -1, server->handler, data); + if (h == NULL) { + say_error("can't create handler fiber, dropping client connection"); + close(fd); + continue; + } + + h->has_peer = true; + fiber_call(h); + } + if (fd < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + say_syserror("accept"); + continue; } } - @finally { - unwait(EV_READ); - } + unwait(EV_READ); } struct fiber * diff --git a/core/tarantool.m b/core/tarantool.m index 0483df8d7056e124a325dd9b7e341cd64a8c1167..d8e5f2a64f119713453fa0f880c3824dd3949b2f 100644 --- a/core/tarantool.m +++ b/core/tarantool.m @@ -100,15 +100,6 @@ load_cfg(struct tarantool_cfg *conf, i32 check_rdonly) return mod_check_config(conf); } -static void -swap_tarantool_cfg(struct tarantool_cfg *old_cfg, struct tarantool_cfg *new_cfg) -{ - struct tarantool_cfg tmp; - - tmp = *old_cfg; - *old_cfg = *new_cfg; - *new_cfg = tmp; -} i32 reload_cfg(struct tbuf *out) @@ -134,10 +125,10 @@ reload_cfg(struct tbuf *out) /* Prepare a copy of the original config file - for confetti, so that it can compare the new + for confetti, so that it can compare the new file with the old one when loading the new file. - Load the new file and return an error if the it - contains a different value for some read-only + Load the new file and return an error if it + contains a different value for some read-only parameter. */ if (dup_tarantool_cfg(&aux_cfg, &cfg) != 0 || @@ -145,8 +136,8 @@ reload_cfg(struct tbuf *out) return -1; /* Load the new configuration file, but - skip the check for read only parameters. - new_cfg contains only defaults and + skip the check for read only parameters. + new_cfg contains only defaults and new settings. */ if (fill_default_tarantool_cfg(&new_cfg) != 0 || diff --git a/include/exceptions.h b/include/exceptions.h index f78206c65d14d836156612270f8a18cc0885a249..52dc6eee54d7dfb9822b7c9b08cb3a381eb99ea2 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -3,6 +3,12 @@ #include <objc/Object.h> +/** The base class for all exceptions. + * + * Note: implements garbage collection (see +alloc + * implementation). + */ + @interface tnt_Exception: Object { @public const char *file; diff --git a/include/fiber.h b/include/fiber.h index c04d24eca28d40ae4cd570621c9c476f1c758241..08f259eb90fbe23ec52bedf18c6dd18e7bf8079f 100644 --- a/include/fiber.h +++ b/include/fiber.h @@ -45,10 +45,16 @@ #define FIBER_NAME_MAXLEN 16 #define FIBER_READING_INBOX 0x1 +/** Can this fiber be cancelled? */ #define FIBER_CANCELLABLE 0x2 +/** Indicates that a fiber has been cancelled. */ #define FIBER_CANCEL 0x4 -@interface tnt_FiberException: tnt_Exception +/** This is thrown by fiber_* API calls when the fiber is + * cancelled. + */ + +@interface tnt_FiberCancelException: tnt_Exception @end struct msg { @@ -165,8 +171,20 @@ void fiber_cleanup(void); void fiber_gc(void); void fiber_call(struct fiber *callee); void fiber_wakeup(struct fiber *f); +/** Cancel a fiber. A cancelled fiber will have + * tnt_FiberCancelException raised in it. + * + * A fiber can be cancelled only if it is + * FIBER_CANCELLABLE flag is set. + */ void fiber_cancel(struct fiber *f); +/** Check if the current fiber has been cancelled. Raises + * tnt_FiberCancelException + */ void fiber_testcancel(void); +/** Make it possible or not possible to cancel the current + * fiber. + */ void fiber_setcancelstate(bool enable); int fiber_connect(struct sockaddr_in *addr); void fiber_sleep(ev_tstamp s);