32 #include <valgrind/valgrind.h>
34 #include <evfibers_private/fiber.h>
36 #ifndef LIST_FOREACH_SAFE
37 #define LIST_FOREACH_SAFE(var, head, field, next_var) \
38 for ((var) = ((head)->lh_first); \
39 (var) && ((next_var) = ((var)->field.le_next), 1); \
44 #ifndef TAILQ_FOREACH_SAFE
45 #define TAILQ_FOREACH_SAFE(var, head, field, next_var) \
46 for ((var) = ((head)->tqh_first); \
47 (var) ? ({ (next_var) = ((var)->field.tqe_next); 1; }) \
53 #define ENSURE_ROOT_FIBER do { \
54 assert(fctx->__p->sp->fiber == &fctx->__p->root); \
57 #define CURRENT_FIBER (fctx->__p->sp->fiber)
58 #define CURRENT_FIBER_ID (fbr_id_pack(CURRENT_FIBER))
59 #define CALLED_BY_ROOT ((fctx->__p->sp - 1)->fiber == &fctx->__p->root)
61 #define unpack_transfer_errno(value, ptr, id) \
63 if (-1 == fbr_id_unpack(fctx, ptr, id)) \
67 #define return_success(value) \
69 fctx->f_errno = FBR_SUCCESS; \
73 #define return_error(value, code) \
75 fctx->f_errno = (code); \
80 static fbr_id_t fbr_id_pack(
struct fbr_fiber *fiber)
82 return ((__uint128_t)fiber->id << 64) | (uint64_t)fiber;
85 static int fbr_id_unpack(
FBR_P_ struct fbr_fiber **ptr,
fbr_id_t id)
87 struct fbr_fiber *fiber;
89 f_id = (uint64_t)(
id >> 64);
90 fiber = (
struct fbr_fiber *)(uint64_t)id;
91 if (fiber->id != f_id)
92 return_error(-1, FBR_ENOFIBER);
98 static void pending_async_cb(EV_P_ ev_async *w, _unused_
int revents)
107 if (TAILQ_EMPTY(&fctx->
__p->pending_fibers)) {
108 ev_async_stop(EV_A_ &fctx->
__p->pending_async);
112 item = TAILQ_FIRST(&fctx->
__p->pending_fibers);
113 assert(item->head == &fctx->
__p->pending_fibers);
117 ev_async_send(EV_A_ &fctx->
__p->pending_async);
119 retval = fbr_transfer(
FBR_A_ item->id);
120 if (-1 == retval && FBR_ENOFIBER != fctx->
f_errno) {
122 " a fiber by id: %s",
127 static void *allocate_in_fiber(
FBR_P_ size_t size,
struct fbr_fiber *in)
129 struct mem_pool *pool_entry;
130 pool_entry = malloc(size +
sizeof(
struct mem_pool));
131 if (NULL == pool_entry) {
133 size +
sizeof(
struct mem_pool));
136 pool_entry->ptr = pool_entry;
137 pool_entry->destructor = NULL;
138 pool_entry->destructor_context = NULL;
139 LIST_INSERT_HEAD(&in->pool, pool_entry, entries);
140 return pool_entry + 1;
144 const char *format, va_list ap)
146 struct fbr_fiber *fiber;
151 if (level > logger->level)
154 fiber = CURRENT_FIBER;
161 case FBR_LOG_WARNING:
162 str_level =
"WARNING";
166 str_level =
"NOTICE";
182 tstamp = ev_now(fctx->
__p->loop);
183 fprintf(stream,
"%.6f %-7s %-16s ", tstamp, str_level, fiber->name);
184 vfprintf(stream, format, ap);
185 fprintf(stream,
"\n");
190 struct fbr_fiber *root;
193 fctx->
__p = malloc(
sizeof(
struct fbr_context_private));
194 LIST_INIT(&fctx->
__p->reclaimed);
195 LIST_INIT(&fctx->
__p->root.children);
196 LIST_INIT(&fctx->
__p->root.pool);
197 TAILQ_INIT(&fctx->
__p->root.destructors);
198 TAILQ_INIT(&fctx->
__p->pending_fibers);
200 root = &fctx->
__p->root;
202 fctx->
__p->last_id = 0;
203 root->id = fctx->
__p->last_id++;
204 coro_create(&root->ctx, NULL, NULL, NULL, 0);
207 logger->
logv = stdio_logger;
208 logger->
level = FBR_LOG_NOTICE;
211 fctx->
__p->sp = fctx->
__p->stack;
212 fctx->
__p->sp->fiber = root;
213 fctx->
__p->backtraces_enabled = 1;
214 fill_trace_info(
FBR_A_ &fctx->
__p->sp->tinfo);
215 fctx->
__p->loop = loop;
216 fctx->
__p->pending_async.data = fctx;
217 fctx->
__p->backtraces_enabled = 0;
218 memset(&fctx->
__p->key_free_mask, 0x00,
219 sizeof(fctx->
__p->key_free_mask));
220 ev_async_init(&fctx->
__p->pending_async, pending_async_cb);
229 return "Invalid argument";
231 return "No such fiber";
233 return "System error, consult system errno";
234 case FBR_EBUFFERMMAP:
235 return "Failed to mmap two adjacent regions";
237 return "Fiber-local key does not exist";
239 return "Unknown error";
245 va_start(ap, format);
253 va_start(ap, format);
261 va_start(ap, format);
269 va_start(ap, format);
277 va_start(ap, format);
282 void id_tailq_i_set(_unused_
FBR_P_
284 struct fbr_fiber *fiber)
286 item->id = fbr_id_pack(fiber);
290 static void reclaim_children(
FBR_P_ struct fbr_fiber *fiber)
293 LIST_FOREACH(f, &fiber->children, entries.children) {
294 fbr_reclaim(
FBR_A_ fbr_id_pack(f));
298 static void fbr_free_in_fiber(_unused_
FBR_P_ _unused_
struct fbr_fiber *fiber,
299 void *ptr,
int destructor);
303 struct fbr_fiber *fiber, *x;
304 struct mem_pool *p, *x2;
306 reclaim_children(
FBR_A_ &fctx->
__p->root);
308 LIST_FOREACH_SAFE(p, &fctx->
__p->root.pool, entries, x2) {
309 fbr_free_in_fiber(
FBR_A_ &fctx->
__p->root, p + 1, 1);
312 LIST_FOREACH_SAFE(fiber, &fctx->
__p->reclaimed, entries.reclaimed, x) {
313 if (0 != munmap(fiber->stack, fiber->stack_size))
314 err(EXIT_FAILURE,
"munmap");
324 fctx->
__p->backtraces_enabled = 1;
326 fctx->
__p->backtraces_enabled = 0;
332 fbr_destructor_remove(
FBR_A_ &ev->item.dtor, 1 );
335 static void post_ev(_unused_
FBR_P_ struct fbr_fiber *fiber,
struct fbr_ev_base *ev)
337 assert(NULL != fiber->ev.waiting);
339 fiber->ev.arrived = 1;
343 static void ev_watcher_cb(_unused_ EV_P_ ev_watcher *w, _unused_
int event)
345 struct fbr_fiber *fiber;
352 retval = fbr_id_unpack(
FBR_A_ &fiber, ev->ev_base.
id);
355 " the watcher callback, but it's id is not valid: %s",
360 post_ev(
FBR_A_ fiber, &ev->ev_base);
362 retval = fbr_transfer(
FBR_A_ fbr_id_pack(fiber));
367 static void fbr_free_in_fiber(_unused_
FBR_P_ _unused_
struct fbr_fiber *fiber,
368 void *ptr,
int destructor)
370 struct mem_pool *pool_entry = NULL;
373 pool_entry = (
struct mem_pool *)ptr - 1;
374 if (pool_entry->ptr != pool_entry) {
376 "fiber memory pool entry", ptr);
377 if (!RUNNING_ON_VALGRIND)
380 LIST_REMOVE(pool_entry, entries);
381 if (destructor && pool_entry->destructor)
382 pool_entry->destructor(
FBR_A_ ptr, pool_entry->destructor_context);
386 static void fiber_cleanup(
FBR_P_ struct fbr_fiber *fiber)
388 struct mem_pool *p, *x;
391 LIST_REMOVE(fiber, entries.children);
392 TAILQ_FOREACH(dtor, &fiber->destructors, entries) {
395 LIST_FOREACH_SAFE(p, &fiber->pool, entries, x) {
396 fbr_free_in_fiber(
FBR_A_ fiber, p + 1, 1);
400 static void filter_fiber_stack(
FBR_P_ struct fbr_fiber *fiber)
402 struct fbr_stack_item *sp;
403 for (sp = fctx->
__p->stack; sp < fctx->__p->sp; sp++) {
404 if (sp->fiber == fiber) {
405 memmove(sp, sp + 1, (fctx->
__p->sp - sp) *
sizeof(*sp));
413 struct fbr_fiber *fiber;
418 unpack_transfer_errno(-1, &fiber,
id);
420 fill_trace_info(
FBR_A_ &fiber->reclaim_tinfo);
421 reclaim_children(
FBR_A_ fiber);
422 fiber_cleanup(
FBR_A_ fiber);
423 fiber->id = fctx->
__p->last_id++;
425 LIST_FOREACH(f, &fctx->
__p->reclaimed, entries.reclaimed) {
429 LIST_INSERT_HEAD(&fctx->
__p->reclaimed, fiber, entries.reclaimed);
431 filter_fiber_stack(
FBR_A_ fiber);
433 if (CURRENT_FIBER == fiber)
441 if (0 == fbr_id_unpack(
FBR_A_ NULL,
id))
448 return CURRENT_FIBER_ID;
451 static void call_wrapper(
FBR_P)
454 struct fbr_fiber *fiber = CURRENT_FIBER;
456 fiber->func(
FBR_A_ fiber->func_arg);
458 retval = fbr_reclaim(
FBR_A_ fbr_id_pack(fiber));
464 enum ev_action_hint {
470 static void item_dtor(_unused_
FBR_P_ void *arg)
475 TAILQ_REMOVE(item->head, item, entries);
487 ev->item.dtor.
func = item_dtor;
488 ev->item.dtor.arg = item;
489 fbr_destructor_add(
FBR_A_ &ev->item.dtor);
494 if (!ev_is_active(e_watcher->
w)) {
495 fbr_destructor_remove(
FBR_A_ &ev->item.dtor,
499 e_watcher->
w->data = e_watcher;
500 ev_set_cb(e_watcher->
w, ev_watcher_cb);
504 if (0 == e_mutex->
mutex->locked_by) {
505 e_mutex->
mutex->locked_by = CURRENT_FIBER_ID;
506 return EV_AH_ARRIVED;
508 id_tailq_i_set(
FBR_A_ item, CURRENT_FIBER);
511 TAILQ_INSERT_TAIL(&e_mutex->
mutex->pending, item, entries);
512 item->head = &e_mutex->
mutex->pending;
516 if (0 == e_cond->
mutex->locked_by) {
517 fbr_destructor_remove(
FBR_A_ &ev->item.dtor,
521 id_tailq_i_set(
FBR_A_ item, CURRENT_FIBER);
524 TAILQ_INSERT_TAIL(&e_cond->
cond->waiting, item, entries);
525 item->head = &e_cond->
cond->waiting;
536 fbr_destructor_remove(
FBR_A_ &ev->item.dtor, 1 );
544 ev_set_cb(e_watcher->
w, NULL);
554 struct fbr_fiber *fiber = CURRENT_FIBER;
556 enum ev_action_hint hint;
560 fiber->ev.waiting = events;
562 for (ev_pptr = events; NULL != *ev_pptr; ev_pptr++) {
563 hint = prepare_ev(
FBR_A_ *ev_pptr);
568 fiber->ev.arrived = 1;
569 (*ev_pptr)->arrived = 1;
572 return_error(-1, FBR_EINVAL);
576 while (0 == fiber->ev.arrived)
579 for (ev_pptr = events; NULL != *ev_pptr; ev_pptr++) {
580 if ((*ev_pptr)->arrived) {
582 finish_ev(
FBR_A_ *ev_pptr);
584 cancel_ev(
FBR_A_ *ev_pptr);
593 n_events = fbr_ev_wait(
FBR_A_ events);
601 struct fbr_fiber *callee;
602 struct fbr_fiber *caller = fctx->
__p->sp->fiber;
604 unpack_transfer_errno(-1, &callee, to);
608 fctx->
__p->sp->fiber = callee;
609 fill_trace_info(
FBR_A_ &fctx->
__p->sp->tinfo);
611 coro_transfer(&caller->ctx, &callee->ctx);
618 struct fbr_fiber *callee = fctx->
__p->sp->fiber;
619 struct fbr_fiber *caller = (--fctx->
__p->sp)->fiber;
621 coro_transfer(&callee->ctx, &caller->ctx);
628 flags = fcntl(fd, F_GETFL, 0);
630 return_error(-1, FBR_ESYSTEM);
633 s = fcntl(fd, F_SETFL, flags);
635 return_error(-1, FBR_ESYSTEM);
643 memset(ev, 0x00,
sizeof(*ev));
645 ev->id = CURRENT_FIBER_ID;
655 static void watcher_io_dtor(_unused_
FBR_P_ void *_arg)
657 struct ev_io *w = _arg;
658 ev_io_stop(fctx->
__p->loop, w);
661 ssize_t fbr_read(
FBR_P_ int fd,
void *buf,
size_t count)
668 ev_io_init(&io, NULL, fd, EV_READ);
669 ev_io_start(fctx->
__p->loop, &io);
670 dtor.
func = watcher_io_dtor;
672 fbr_destructor_add(
FBR_A_ &dtor);
674 fbr_ev_watcher_init(
FBR_A_ &watcher, (ev_watcher *)&io);
675 fbr_ev_wait_one(
FBR_A_ &watcher.ev_base);
677 fbr_destructor_remove(
FBR_A_ &dtor, 0 );
679 r = read(fd, buf, count);
680 }
while (-1 == r && EINTR == errno);
682 ev_io_stop(fctx->
__p->loop, &io);
687 ssize_t fbr_read_all(
FBR_P_ int fd,
void *buf,
size_t count)
695 ev_io_init(&io, NULL, fd, EV_READ);
696 ev_io_start(fctx->
__p->loop, &io);
697 dtor.
func = watcher_io_dtor;
699 fbr_destructor_add(
FBR_A_ &dtor);
701 fbr_ev_watcher_init(
FBR_A_ &watcher, (ev_watcher *)&io);
703 while (count != done) {
705 fbr_ev_wait_one(
FBR_A_ &watcher.ev_base);
707 r = read(fd, buf + done, count - done);
724 fbr_destructor_remove(
FBR_A_ &dtor, 0 );
725 ev_io_stop(fctx->
__p->loop, &io);
726 return (ssize_t)done;
729 fbr_destructor_remove(
FBR_A_ &dtor, 0 );
730 ev_io_stop(fctx->
__p->loop, &io);
734 ssize_t fbr_readline(
FBR_P_ int fd,
void *buffer,
size_t n)
741 if (n <= 0 || buffer == NULL) {
750 num_read = fbr_read(
FBR_A_ fd, &ch, 1);
752 if (num_read == -1) {
758 }
else if (num_read == 0) {
765 if (total_read < n - 1) {
779 ssize_t fbr_write(
FBR_P_ int fd,
const void *buf,
size_t count)
786 ev_io_init(&io, NULL, fd, EV_WRITE);
787 ev_io_start(fctx->
__p->loop, &io);
788 dtor.
func = watcher_io_dtor;
790 fbr_destructor_add(
FBR_A_ &dtor);
792 fbr_ev_watcher_init(
FBR_A_ &watcher, (ev_watcher *)&io);
793 fbr_ev_wait_one(
FBR_A_ &watcher.ev_base);
796 r = write(fd, buf, count);
797 }
while (-1 == r && EINTR == errno);
799 fbr_destructor_remove(
FBR_A_ &dtor, 0 );
800 ev_io_stop(fctx->
__p->loop, &io);
804 ssize_t fbr_write_all(
FBR_P_ int fd,
const void *buf,
size_t count)
812 ev_io_init(&io, NULL, fd, EV_WRITE);
813 ev_io_start(fctx->
__p->loop, &io);
814 dtor.
func = watcher_io_dtor;
816 fbr_destructor_add(
FBR_A_ &dtor);
818 fbr_ev_watcher_init(
FBR_A_ &watcher, (ev_watcher *)&io);
820 while (count != done) {
822 fbr_ev_wait_one(
FBR_A_ &watcher.ev_base);
824 r = write(fd, buf + done, count - done);
839 fbr_destructor_remove(
FBR_A_ &dtor, 0 );
840 ev_io_stop(fctx->
__p->loop, &io);
841 return (ssize_t)done;
844 fbr_destructor_remove(
FBR_A_ &dtor, 0 );
845 ev_io_stop(fctx->
__p->loop, &io);
849 ssize_t fbr_recvfrom(
FBR_P_ int sockfd,
void *buf,
size_t len,
int flags,
850 struct sockaddr *src_addr, socklen_t *addrlen)
856 ev_io_init(&io, NULL, sockfd, EV_READ);
857 ev_io_start(fctx->
__p->loop, &io);
858 dtor.
func = watcher_io_dtor;
860 fbr_destructor_add(
FBR_A_ &dtor);
862 fbr_ev_watcher_init(
FBR_A_ &watcher, (ev_watcher *)&io);
863 fbr_ev_wait_one(
FBR_A_ &watcher.ev_base);
865 fbr_destructor_remove(
FBR_A_ &dtor, 0 );
866 ev_io_stop(fctx->
__p->loop, &io);
868 return recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
871 ssize_t fbr_sendto(
FBR_P_ int sockfd,
const void *buf,
size_t len,
int flags,
const
872 struct sockaddr *dest_addr, socklen_t addrlen)
878 ev_io_init(&io, NULL, sockfd, EV_WRITE);
879 ev_io_start(fctx->
__p->loop, &io);
880 dtor.
func = watcher_io_dtor;
882 fbr_destructor_add(
FBR_A_ &dtor);
884 fbr_ev_watcher_init(
FBR_A_ &watcher, (ev_watcher *)&io);
885 fbr_ev_wait_one(
FBR_A_ &watcher.ev_base);
887 fbr_destructor_remove(
FBR_A_ &dtor, 0 );
888 ev_io_stop(fctx->
__p->loop, &io);
890 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
893 int fbr_accept(
FBR_P_ int sockfd,
struct sockaddr *addr, socklen_t *addrlen)
900 ev_io_init(&io, NULL, sockfd, EV_READ);
901 ev_io_start(fctx->
__p->loop, &io);
902 dtor.
func = watcher_io_dtor;
904 fbr_destructor_add(
FBR_A_ &dtor);
906 fbr_ev_watcher_init(
FBR_A_ &watcher, (ev_watcher *)&io);
907 fbr_ev_wait_one(
FBR_A_ &watcher.ev_base);
910 r = accept(sockfd, addr, addrlen);
911 }
while (-1 == r && EINTR == errno);
913 fbr_destructor_remove(
FBR_A_ &dtor, 0 );
914 ev_io_stop(fctx->
__p->loop, &io);
919 static void watcher_timer_dtor(_unused_
FBR_P_ void *_arg)
921 struct ev_timer *w = _arg;
922 ev_timer_stop(fctx->
__p->loop, w);
925 ev_tstamp fbr_sleep(
FBR_P_ ev_tstamp seconds)
930 ev_tstamp expected = ev_now(fctx->
__p->loop) + seconds;
932 ev_timer_init(&timer, NULL, seconds, 0.);
933 ev_timer_start(fctx->
__p->loop, &timer);
934 dtor.
func = watcher_timer_dtor;
936 fbr_destructor_add(
FBR_A_ &dtor);
938 fbr_ev_watcher_init(
FBR_A_ &watcher, (ev_watcher *)&timer);
939 fbr_ev_wait_one(
FBR_A_ &watcher.ev_base);
941 fbr_destructor_remove(
FBR_A_ &dtor, 0 );
942 ev_timer_stop(fctx->
__p->loop, &timer);
944 return max(0., expected - ev_now(fctx->
__p->loop));
947 static size_t round_up_to_page_size(
size_t size)
952 sz = sysconf(_SC_PAGESIZE);
953 remainder = size % sz;
956 return size + sz - remainder;
962 struct fbr_fiber *fiber;
963 if (!LIST_EMPTY(&fctx->
__p->reclaimed)) {
964 fiber = LIST_FIRST(&fctx->
__p->reclaimed);
965 LIST_REMOVE(fiber, entries.reclaimed);
967 fiber = malloc(
sizeof(
struct fbr_fiber));
968 memset(fiber, 0x00,
sizeof(
struct fbr_fiber));
971 stack_size = round_up_to_page_size(stack_size);
972 fiber->stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
973 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
974 if (MAP_FAILED == fiber->stack)
975 err(EXIT_FAILURE,
"mmap failed");
976 fiber->stack_size = stack_size;
977 (void)VALGRIND_STACK_REGISTER(fiber->stack, fiber->stack +
979 fiber->id = fctx->
__p->last_id++;
981 coro_create(&fiber->ctx, (coro_func)call_wrapper,
FBR_A, fiber->stack,
983 fiber->call_list = NULL;
984 fiber->call_list_size = 0;
985 LIST_INIT(&fiber->children);
986 LIST_INIT(&fiber->pool);
987 TAILQ_INIT(&fiber->destructors);
990 fiber->func_arg = arg;
991 LIST_INSERT_HEAD(&CURRENT_FIBER->children, fiber, entries.children);
992 fiber->parent = CURRENT_FIBER;
993 return fbr_id_pack(fiber);
998 struct fbr_fiber *fiber, *parent;
1000 unpack_transfer_errno(-1, &parent, parent_id);
1002 parent = &fctx->
__p->root;
1003 fiber = CURRENT_FIBER;
1004 LIST_REMOVE(fiber, entries.children);
1005 LIST_INSERT_HEAD(&parent->children, fiber, entries.children);
1006 fiber->parent = parent;
1012 struct fbr_fiber *fiber = CURRENT_FIBER;
1013 if (fiber->parent == &fctx->
__p->root)
1015 return fbr_id_pack(fiber->parent);
1018 void *fbr_calloc(
FBR_P_ unsigned int nmemb,
size_t size)
1021 ptr = allocate_in_fiber(
FBR_A_ nmemb * size, CURRENT_FIBER);
1022 memset(ptr, 0x00, nmemb * size);
1028 return allocate_in_fiber(
FBR_A_ size, CURRENT_FIBER);
1034 struct mem_pool *pool_entry;
1035 pool_entry = (
struct mem_pool *)ptr - 1;
1036 pool_entry->destructor = func;
1037 pool_entry->destructor_context = context;
1042 fbr_free_in_fiber(
FBR_A_ CURRENT_FIBER, ptr, 1);
1047 fbr_free_in_fiber(
FBR_A_ CURRENT_FIBER, ptr, 0);
1052 struct fbr_stack_item *ptr = fctx->
__p->sp;
1053 (*log)(
FBR_A_ "%s",
"Fiber call stack:");
1054 (*log)(FBR_A_
"%s",
"-------------------------------");
1055 while (ptr >= fctx->
__p->stack) {
1056 (*log)(FBR_A_
"fiber_call: %p\t%s",
1059 print_trace_info(FBR_A_ &ptr->tinfo, log);
1060 (*log)(FBR_A_
"%s",
"-------------------------------");
1068 was_empty = TAILQ_EMPTY(&fctx->
__p->pending_fibers);
1069 TAILQ_INSERT_TAIL(&fctx->
__p->pending_fibers, item, entries);
1070 item->head = &fctx->
__p->pending_fibers;
1071 if (was_empty && !TAILQ_EMPTY(&fctx->
__p->pending_fibers)) {
1072 ev_async_start(fctx->
__p->loop, &fctx->
__p->pending_async);
1074 ev_async_send(fctx->
__p->loop, &fctx->
__p->pending_async);
1077 static void transfer_later_tailq(
FBR_P_ struct fbr_id_tailq *tailq)
1081 TAILQ_FOREACH(item, tailq, entries) {
1082 item->head = &fctx->
__p->pending_fibers;
1084 was_empty = TAILQ_EMPTY(&fctx->
__p->pending_fibers);
1085 TAILQ_CONCAT(&fctx->
__p->pending_fibers, tailq, entries);
1086 if (was_empty && !TAILQ_EMPTY(&fctx->
__p->pending_fibers)) {
1087 ev_async_start(fctx->
__p->loop, &fctx->
__p->pending_async);
1089 ev_async_send(fctx->
__p->loop, &fctx->
__p->pending_async);
1101 mutex->locked_by = 0;
1102 TAILQ_INIT(&mutex->pending);
1109 fbr_ev_mutex_init(
FBR_A_ &ev, mutex);
1110 fbr_ev_wait_one(
FBR_A_ &ev.ev_base);
1111 assert(mutex->locked_by == CURRENT_FIBER_ID);
1116 if (0 == mutex->locked_by) {
1117 mutex->locked_by = CURRENT_FIBER_ID;
1126 struct fbr_fiber *fiber = NULL;
1128 if (TAILQ_EMPTY(&mutex->pending)) {
1129 mutex->locked_by = 0;
1133 TAILQ_FOREACH_SAFE(item, &mutex->pending, entries, x) {
1134 assert(item->head == &mutex->pending);
1135 TAILQ_REMOVE(&mutex->pending, item, entries);
1136 if (-1 == fbr_id_unpack(
FBR_A_ &fiber, item->id)) {
1138 " to find a fiber by id: %s",
1145 mutex->locked_by = item->id;
1146 post_ev(
FBR_A_ fiber, item->ev);
1148 transfer_later(
FBR_A_ item);
1169 TAILQ_INIT(&cond->waiting);
1183 if (0 == mutex->locked_by)
1184 return_error(-1, FBR_EINVAL);
1186 fbr_ev_cond_var_init(
FBR_A_ &ev, cond, mutex);
1187 fbr_ev_wait_one(
FBR_A_ &ev.ev_base);
1194 struct fbr_fiber *fiber;
1195 if (TAILQ_EMPTY(&cond->waiting))
1197 TAILQ_FOREACH(item, &cond->waiting, entries) {
1198 if(-1 == fbr_id_unpack(
FBR_A_ &fiber, item->id)) {
1199 assert(FBR_ENOFIBER == fctx->
f_errno);
1202 post_ev(
FBR_A_ fiber, item->ev);
1204 transfer_later_tailq(
FBR_A_ &cond->waiting);
1210 struct fbr_fiber *fiber;
1211 if (TAILQ_EMPTY(&cond->waiting))
1213 item = TAILQ_FIRST(&cond->waiting);
1214 if(-1 == fbr_id_unpack(
FBR_A_ &fiber, item->id)) {
1215 assert(FBR_ENOFIBER == fctx->
f_errno);
1218 post_ev(
FBR_A_ fiber, item->ev);
1220 assert(item->head == &cond->waiting);
1221 TAILQ_REMOVE(&cond->waiting, item, entries);
1222 transfer_later(
FBR_A_ item);
1227 buffer->vrb = vrb_new(size, NULL);
1228 if (NULL == buffer->vrb)
1229 return_error(-1, FBR_ESYSTEM);
1230 buffer->prepared_bytes = 0;
1231 buffer->waiting_bytes = 0;
1241 vrb_destroy(buffer->vrb);
1251 if (size > vrb_capacity(buffer->vrb))
1252 return_error(NULL, FBR_EINVAL);
1254 fbr_mutex_lock(
FBR_A_ &buffer->write_mutex);
1256 while (buffer->prepared_bytes > 0)
1257 fbr_cond_wait(
FBR_A_ &buffer->committed_cond,
1258 &buffer->write_mutex);
1260 assert(0 == buffer->prepared_bytes);
1262 buffer->prepared_bytes = size;
1264 while ((
size_t)vrb_space_len(buffer->vrb) < size)
1265 fbr_cond_wait(
FBR_A_ &buffer->bytes_freed_cond,
1266 &buffer->write_mutex);
1268 return vrb_space_ptr(buffer->vrb);
1273 vrb_give(buffer->vrb, buffer->prepared_bytes);
1274 buffer->prepared_bytes = 0;
1275 fbr_cond_signal(
FBR_A_ &buffer->committed_cond);
1276 fbr_mutex_unlock(
FBR_A_ &buffer->write_mutex);
1281 buffer->prepared_bytes = 0;
1282 fbr_cond_signal(
FBR_A_ &buffer->committed_cond);
1283 fbr_mutex_unlock(
FBR_A_ &buffer->write_mutex);
1289 if (size > vrb_capacity(buffer->vrb))
1290 return_error(NULL, FBR_EINVAL);
1292 fbr_mutex_lock(
FBR_A_ &buffer->read_mutex);
1294 while ((
size_t)vrb_data_len(buffer->vrb) < size) {
1295 retval = fbr_cond_wait(
FBR_A_ &buffer->committed_cond,
1296 &buffer->read_mutex);
1297 assert(0 == retval);
1300 buffer->waiting_bytes = size;
1302 return_success(vrb_data_ptr(buffer->vrb));
1307 vrb_take(buffer->vrb, buffer->waiting_bytes);
1309 fbr_cond_signal(
FBR_A_ &buffer->bytes_freed_cond);
1310 fbr_mutex_unlock(
FBR_A_ &buffer->read_mutex);
1315 fbr_mutex_unlock(
FBR_A_ &buffer->read_mutex);
1320 return vrb_data_len(buffer->vrb);
1325 return vrb_space_len(buffer->vrb);
1330 struct fbr_fiber *fiber;
1331 unpack_transfer_errno(NULL, &fiber,
id);
1332 return_success(fiber->user_data);
1337 struct fbr_fiber *fiber;
1338 unpack_transfer_errno(-1, &fiber,
id);
1339 fiber->user_data = data;
1345 struct fbr_fiber *fiber = CURRENT_FIBER;
1346 TAILQ_INSERT_TAIL(&fiber->destructors, dtor, entries);
1353 struct fbr_fiber *fiber = CURRENT_FIBER;
1355 if (0 == dtor->active)
1358 TAILQ_REMOVE(&fiber->destructors, dtor, entries);
1360 dtor->func(
FBR_A_ dtor->arg);
1364 static inline int ffsll(uint64_t val)
1367 return __builtin_ffsll(val);
1372 return 0 == (fctx->
__p->key_free_mask & (1 << key));
1377 fctx->
__p->key_free_mask &= ~(1 << key);
1382 fctx->
__p->key_free_mask |= (1 << key);
1389 register_key(
FBR_A_ key);
1396 if (!is_key_registered(
FBR_A_ key))
1397 return_error(-1, FBR_ENOKEY);
1399 unregister_key(
FBR_A_ key);
1406 struct fbr_fiber *fiber;
1408 unpack_transfer_errno(-1, &fiber,
id);
1410 if (!is_key_registered(
FBR_A_ key))
1411 return_error(-1, FBR_ENOKEY);
1413 fiber->key_data[key] = value;
1419 struct fbr_fiber *fiber;
1421 unpack_transfer_errno(NULL, &fiber,
id);
1423 if (!is_key_registered(
FBR_A_ key))
1424 return_error(NULL, FBR_ENOKEY);
1426 return fiber->key_data[key];
1431 struct fbr_fiber *fiber;
1432 unpack_transfer_errno(NULL, &fiber,
id);
1433 return_success(fiber->name);
1438 struct fbr_fiber *fiber;
1439 unpack_transfer_errno(-1, &fiber,
id);