/** * Copyright (C) Mellanox Technologies Ltd. 2001-2011. ALL RIGHTS RESERVED. * * See file LICENSE for terms. */ #ifndef UCS_ASYNC_H_ #define UCS_ASYNC_H_ #include "thread.h" #include "signal.h" #include "async_fwd.h" #include #include #include #include BEGIN_C_DECLS /** @file async.h */ /** * Async event context. Manages timer and fd notifications. */ struct ucs_async_context { union { ucs_async_thread_context_t thread; ucs_async_signal_context_t signal; int poll_block; }; ucs_async_mode_t mode; /* Event delivery mode */ volatile uint32_t num_handlers; /* Number of event and timer handlers */ ucs_mpmc_queue_t missed; /* Miss queue */ ucs_time_t last_wakeup; /* time of the last wakeup */ }; /** * @ingroup UCS_RESOURCE * * GLobal initialization and cleanup of async event handling. */ void ucs_async_global_init(); void ucs_async_global_cleanup(); /** * Initialize an asynchronous execution context. The context is not allocated. * To allocate the context, please use public version of the * function @ref ucs_async_context_create * This can be used to ensure safe event delivery. * * @param async Event context to initialize. * @param mode Indicates whether to use signals or polling threads * for waiting. * * @return Error code as defined by @ref ucs_status_t. */ ucs_status_t ucs_async_context_init(ucs_async_context_t *async, ucs_async_mode_t mode); /** * Clean up the async context, and release system resources if possible. * * @param async Asynchronous context to clean up. */ void ucs_async_context_cleanup(ucs_async_context_t *async); /** * Check if an async callback was missed because the main thread has blocked * the async context. This works as edge-triggered. * Should be called with the lock held. */ static inline int ucs_async_check_miss(ucs_async_context_t *async) { if (ucs_unlikely(!ucs_mpmc_queue_is_empty(&async->missed))) { __ucs_async_poll_missed(async); return 1; } else if (ucs_unlikely(async->mode == UCS_ASYNC_MODE_POLL)) { ucs_async_poll(async); return 1; } return 0; } /** * Block the async handler (if its currently running, wait until it exits and * block it then). Used to serialize accesses with the async handler. * * @param event Event context to block events for. * @note This function might wait until a currently running callback returns. */ #define UCS_ASYNC_BLOCK(_async) \ do { \ if ((_async)->mode == UCS_ASYNC_MODE_THREAD_SPINLOCK) { \ ucs_spin_lock(&(_async)->thread.spinlock); \ } else if ((_async)->mode == UCS_ASYNC_MODE_THREAD_MUTEX) { \ (void)pthread_mutex_lock(&(_async)->thread.mutex); \ } else if ((_async)->mode == UCS_ASYNC_MODE_SIGNAL) { \ UCS_ASYNC_SIGNAL_BLOCK(_async); \ } else { \ ++(_async)->poll_block; \ } \ } while(0) /** * Unblock asynchronous event delivery, and invoke pending callbacks. * * @param event Event context to unblock events for. */ #define UCS_ASYNC_UNBLOCK(_async) \ do { \ if ((_async)->mode == UCS_ASYNC_MODE_THREAD_SPINLOCK) { \ ucs_spin_unlock(&(_async)->thread.spinlock); \ } else if ((_async)->mode == UCS_ASYNC_MODE_THREAD_MUTEX) { \ (void)pthread_mutex_unlock(&(_async)->thread.mutex); \ } else if ((_async)->mode == UCS_ASYNC_MODE_SIGNAL) { \ UCS_ASYNC_SIGNAL_UNBLOCK(_async); \ } else { \ --(_async)->poll_block; \ } \ } while (0) #define UCS_ASYNC_THREAD_LOCK_TYPE (RUNNING_ON_VALGRIND ? \ UCS_ASYNC_MODE_THREAD_MUTEX : UCS_ASYNC_MODE_THREAD_SPINLOCK) END_C_DECLS #endif