diff options
Diffstat (limited to 'include/libtf/fiber.h')
-rw-r--r-- | include/libtf/fiber.h | 141 |
1 files changed, 102 insertions, 39 deletions
diff --git a/include/libtf/fiber.h b/include/libtf/fiber.h index d5c6153..f97e963 100644 --- a/include/libtf/fiber.h +++ b/include/libtf/fiber.h @@ -16,64 +16,127 @@ #include <errno.h> #include <libtf/defines.h> #include <libtf/heap.h> +#include <libtf/list.h> -/* Fiber wakeup reasons */ -#define TF_WAKEUP_NONE 0 -#define TF_WAKEUP_IMMEDIATE -EAGAIN -#define TF_WAKEUP_KILL -EINTR -#define TF_WAKEUP_TIMEOUT -ETIME -#define TF_WAKEUP_THIS_TIMEOUT -ETIMEDOUT -#define TF_WAKEUP_FD -EIO +/* Inter-fibre calls */ +struct tf_fiber; +struct tf_ifc; +typedef void (*tf_ifc_handler_t)(void *fiber, struct tf_ifc *msg); -/* Fiber management */ -struct tf_scheduler; -typedef void (*tf_fiber_proc)(void *fiber); +struct tf_ifc { + union { + struct tf_ifc *next; + struct tf_list_node list; + }; + tf_ifc_handler_t handler; + struct tf_fiber * sender; +}; -void *__tf_fiber_create(tf_fiber_proc fiber_main, int private_size); -void *tf_fiber_create(tf_fiber_proc fiber_main, int private_size); -void *tf_fiber_get(void *data); -void tf_fiber_put(void *data); -void __tf_fiber_wakeup(void *data, int wakeup_type); -void __tf_fiber_wakeup_heapnode(struct tf_heap_node *node); -int __tf_fiber_schedule(void); -int __tf_fiber_bind_scheduler(struct tf_scheduler *sched); -int __tf_fiber_release_scheduler(struct tf_scheduler *sched); +void tf_ifc_queue(void *fiber, struct tf_ifc *msg, tf_ifc_handler_t handler); +void tf_ifc_complete(void *fiber, struct tf_ifc *msg, tf_ifc_handler_t handler); +void tf_ifc_process(void); +void tf_ifc_process_unordered(void); -void tf_fiber_exit(void) attribute_noreturn; -void tf_fiber_kill(void *fiber); -int tf_fiber_yield(void); +/* Timeouts */ +struct tf_timeout_manager { + struct tf_heap_head heap; + unsigned int num_fibers; +}; + +struct tf_timeout_client { + struct tf_timeout_manager * manager; + tf_mtime_t value; + tf_mtime_t latched; + struct tf_heap_node heap_node; + struct tf_ifc ifc; +}; -/* Scheduling and fiber management */ struct tf_timeout { - tf_mtime_t saved_timeout; - unsigned int timeout_change; + tf_mtime_t saved_timeout; + tf_mtime_t my_timeout; }; -#define tf_timed(func, timeout) \ +static inline int tf_timeout_expired(struct tf_timeout *to) +{ + return tf_mtime_diff(to->my_timeout, tf_mtime_now()) <= 0; +} + +struct tf_timeout_fiber *tf_timeout_fiber_create(void); +void tf_timeout_adjust(struct tf_timeout_client *tc); +void tf_timeout_delete(struct tf_timeout_client *tc); + +#define tf_timed(__to, func, timeout) \ ({ \ - struct tf_timeout __timeout; \ - tf_timeout_push(&__timeout, timeout); \ - tf_timeout_pop(&__timeout, (func)); \ + tf_timeout_push(__to, timeout); \ + tf_timeout_pop(__to, (func)); \ }) -void tf_timeout_push(struct tf_timeout *timeout, tf_mtime_diff_t milliseconds); -int __tf_timeout_pop(struct tf_timeout *timeout, int err); +/* Fibres and their management */ +typedef void *tf_uctx_t; + +struct tf_fiber { + unsigned int ref_count; + unsigned int flags; + tf_uctx_t context; + tf_uctx_t return_context; + struct tf_list_node queue_node; + struct tf_list_head wakeup_q; + struct tf_timeout_client timeout; + struct tf_ifc * pending_ifc; + char data[TF_EMPTY_ARRAY]; +}; + +typedef void (*tf_fiber_proc)(void *fiber); + +void *__tf_fiber_create(tf_fiber_proc fiber_main, int private_size); +void *tf_fiber_create(tf_fiber_proc fiber_main, int private_size); +void *tf_fiber_get(void *fiber); +void tf_fiber_put(void *fiber); +int tf_fiber_run(void *fiber); +void tf_fiber_kill(void *fiber); + +void tf_fiber_wakeup(struct tf_fiber *fiber); +int tf_fiber_schedule(void); -static inline int tf_timeout_pop(struct tf_timeout *timeout, int err) +void tf_fiber_exit(void) attribute_noreturn; + +static inline struct tf_fiber *tf_vmach_get_current_fiber(void) { - if (unlikely(timeout->timeout_change)) - return __tf_timeout_pop(timeout, err); + extern __thread struct tf_fiber *tf_current_fiber; + return tf_current_fiber; +} + +static inline void tf_timeout_push(struct tf_timeout *to, tf_mtime_diff_t ms) +{ + struct tf_fiber *f = tf_vmach_get_current_fiber(); + + to->saved_timeout = f->timeout.value; + to->my_timeout = tf_mtime_now() + ms; + if (f->timeout.value == 0 || + tf_mtime_diff(to->my_timeout, f->timeout.value) < 0) + f->timeout.value = to->my_timeout; +} + +static inline int tf_timeout_pop(struct tf_timeout *to, int err) +{ + struct tf_fiber *f = tf_vmach_get_current_fiber(); + + f->timeout.value = to->saved_timeout; return err; } static inline -int tf_msleep(tf_mtime_diff_t milliseconds) +int tf_msleep(tf_mtime_diff_t ms) { + struct tf_timeout to; int r; - r = tf_timed(__tf_fiber_schedule(), milliseconds); - if (r == TF_WAKEUP_THIS_TIMEOUT) - r = 0; - return r; + + tf_timeout_push(&to, ms); + do { + r = tf_fiber_schedule(); + } while (r != -ETIME); + + return tf_timeout_pop(&to, r); } #endif |