/* fiber.h - libtf fiber manager header * * Copyright (C) 2009-2010 Timo Teräs * All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 or later as * published by the Free Software Foundation. * * See http://www.gnu.org/ for details. */ #ifndef TF_FIBER_H #define TF_FIBER_H #include #include #include #include /* Inter-fibre calls */ struct tf_fiber; struct tf_ifc; typedef void (*tf_ifc_handler_t)(void *fiber, struct tf_ifc *msg); struct tf_ifc { union { struct tf_ifc *next; struct tf_list_node list; }; tf_ifc_handler_t handler; struct tf_fiber * sender; }; 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); /* 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; }; struct tf_timeout { tf_mtime_t saved_timeout; tf_mtime_t my_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) \ ({ \ tf_timeout_push(__to, timeout); \ tf_timeout_pop(__to, (func)); \ }) /* 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); void tf_fiber_exit(void) attribute_noreturn; static inline struct tf_fiber *tf_vmach_get_current_fiber(void) { 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 ms) { struct tf_timeout to; int r; tf_timeout_push(&to, ms); do { r = tf_fiber_schedule(); } while (r != -ETIME); return tf_timeout_pop(&to, r); } #endif