static ucs_status_t ucs_async_handler_dispatch(ucs_async_handler_t *handler) { ucs_async_context_t *async; ucs_async_mode_t mode; ucs_status_t status; mode = handler->mode; async = handler->async; if (async != NULL) { async->last_wakeup = ucs_get_time(); } if (async == NULL) { ucs_trace_async("calling async handler " UCS_ASYNC_HANDLER_FMT, UCS_ASYNC_HANDLER_ARG(handler)); handler->cb(handler->id, handler->arg); } else if (ucs_async_method_call(mode, context_try_block, async)) { ucs_trace_async("calling async handler " UCS_ASYNC_HANDLER_FMT, UCS_ASYNC_HANDLER_ARG(handler)); handler->cb(handler->id, handler->arg); ucs_async_method_call(mode, context_unblock, async); } else /* async != NULL */ { ucs_trace_async("missed " UCS_ASYNC_HANDLER_FMT ", last_wakeup %lu", UCS_ASYNC_HANDLER_ARG(handler), async->last_wakeup); if (ucs_atomic_cswap32(&handler->missed, 0, 1) == 0) { status = ucs_mpmc_queue_push(&async->missed, handler->id); if (status != UCS_OK) { ucs_fatal("Failed to push event %d to miss queue: %s", handler->id, ucs_status_string(status)); } } return UCS_ERR_NO_PROGRESS; } return UCS_OK; }
/* add new handler to the table */ static ucs_status_t ucs_async_handler_add(ucs_async_handler_t *handler) { int hash_extra_status; ucs_status_t status; khiter_t hash_it; pthread_rwlock_wrlock(&ucs_async_global_context.handlers_lock); ucs_assert_always(handler->refcount == 1); hash_it = kh_put(ucs_async_handler, &ucs_async_global_context.handlers, handler->id, &hash_extra_status); if (hash_extra_status == -1) { ucs_error("Failed to add async handler " UCS_ASYNC_HANDLER_FMT " to hash", UCS_ASYNC_HANDLER_ARG(handler)); status = UCS_ERR_NO_MEMORY; goto out_unlock; } else if (hash_extra_status == 0) { ucs_error("Async handler " UCS_ASYNC_HANDLER_FMT " exists - cannot add %s()", UCS_ASYNC_HANDLER_ARG(kh_value(&ucs_async_global_context.handlers, hash_it)), ucs_debug_get_symbol_name(handler->cb)); status = UCS_ERR_ALREADY_EXISTS; goto out_unlock; } ucs_assert_always(!ucs_async_handler_kh_is_end(hash_it)); kh_value(&ucs_async_global_context.handlers, hash_it) = handler; ucs_debug("added async handler " UCS_ASYNC_HANDLER_FMT " to hash", UCS_ASYNC_HANDLER_ARG(handler)); status = UCS_OK; out_unlock: pthread_rwlock_unlock(&ucs_async_global_context.handlers_lock); return status; }
/* add new handler to the table */ static ucs_status_t ucs_async_handler_add(int min_id, int max_id, ucs_async_handler_t *handler) { int hash_extra_status; ucs_status_t status; khiter_t hash_it; int i, id; pthread_rwlock_wrlock(&ucs_async_global_context.handlers_lock); handler->id = -1; ucs_assert_always(handler->refcount == 1); /* * Search for an empty key in the range [min_id, max_id) * ucs_async_global_context.handler_id is used to generate "unique" keys. */ for (i = min_id; i < max_id; ++i) { id = min_id + (ucs_atomic_fadd32(&ucs_async_global_context.handler_id, 1) % (max_id - min_id)); hash_it = kh_put(ucs_async_handler, &ucs_async_global_context.handlers, id, &hash_extra_status); if (hash_extra_status == -1) { ucs_error("Failed to add async handler " UCS_ASYNC_HANDLER_FMT " to hash", UCS_ASYNC_HANDLER_ARG(handler)); status = UCS_ERR_NO_MEMORY; goto out_unlock; } else if (hash_extra_status != 0) { handler->id = id; ucs_assert(id != -1); break; } } if (handler->id == -1) { ucs_error("Cannot add async handler %s() - id range [%d..%d) is full", ucs_debug_get_symbol_name(handler->cb), min_id, max_id); status = UCS_ERR_ALREADY_EXISTS; goto out_unlock; } ucs_assert_always(!ucs_async_handler_kh_is_end(hash_it)); kh_value(&ucs_async_global_context.handlers, hash_it) = handler; ucs_debug("added async handler " UCS_ASYNC_HANDLER_FMT " to hash", UCS_ASYNC_HANDLER_ARG(handler)); status = UCS_OK; out_unlock: pthread_rwlock_unlock(&ucs_async_global_context.handlers_lock); return status; }
/* decrement reference count and release the handler if reached 0 */ static void ucs_async_handler_put(ucs_async_handler_t *handler) { if (ucs_atomic_fadd32(&handler->refcount, -1) > 1) { return; } ucs_debug("release async handler " UCS_ASYNC_HANDLER_FMT, UCS_ASYNC_HANDLER_ARG(handler)); ucs_free(handler); }
/* remove from hash and return the handler */ static ucs_async_handler_t *ucs_async_handler_extract(int id) { ucs_async_handler_t *handler; khiter_t hash_it; pthread_rwlock_wrlock(&ucs_async_global_context.handlers_lock); hash_it = ucs_async_handler_kh_get(id); if (ucs_async_handler_kh_is_end(hash_it)) { ucs_debug("async handler [id=%d] not found in hash table", id); handler = NULL; } else { handler = kh_value(&ucs_async_global_context.handlers, hash_it); ucs_assert_always(handler->id == id); kh_del(ucs_async_handler, &ucs_async_global_context.handlers, hash_it); ucs_debug("removed async handler " UCS_ASYNC_HANDLER_FMT " from hash", UCS_ASYNC_HANDLER_ARG(handler)); } pthread_rwlock_unlock(&ucs_async_global_context.handlers_lock); return handler; }