#ifndef UCS_ARBITER_H_
#define UCS_ARBITER_H_
#include <ucs/sys/compiler_def.h>
#include <ucs/datastruct/list.h>
#include <ucs/type/status.h>
#include <stdio.h>
#include <ucs/debug/assert.h>
typedef struct ucs_arbiter ucs_arbiter_t;
typedef struct ucs_arbiter_group ucs_arbiter_group_t;
typedef struct ucs_arbiter_elem ucs_arbiter_elem_t;
typedef enum {
UCS_ARBITER_CB_RESULT_REMOVE_ELEM,
UCS_ARBITER_CB_RESULT_NEXT_GROUP,
UCS_ARBITER_CB_RESULT_DESCHED_GROUP,
UCS_ARBITER_CB_RESULT_RESCHED_GROUP,
UCS_ARBITER_CB_RESULT_STOP
} ucs_arbiter_cb_result_t;
#if UCS_ENABLE_ASSERT
#define UCS_ARBITER_GROUP_GUARD_DEFINE int guard
#define UCS_ARBITER_GROUP_GUARD_INIT(_group) (_group)->guard = 0
#define UCS_ARBITER_GROUP_GUARD_ENTER(_group) (_group)->guard++
#define UCS_ARBITER_GROUP_GUARD_EXIT(_group) (_group)->guard--
#define UCS_ARBITER_GROUP_GUARD_CHECK(_group) \
ucs_assertv((_group)->guard == 0, \
"scheduling arbiter group %p while it's being dispatched", _group)
#define UCS_ARBITER_GROUP_ARBITER_DEFINE ucs_arbiter_t *arbiter
#define UCS_ARBITER_GROUP_ARBITER_SET(_group, _arbiter) \
(_group)->arbiter = (_arbiter)
#else
#define UCS_ARBITER_GROUP_GUARD_DEFINE
#define UCS_ARBITER_GROUP_GUARD_INIT(_group)
#define UCS_ARBITER_GROUP_GUARD_ENTER(_group)
#define UCS_ARBITER_GROUP_GUARD_EXIT(_group)
#define UCS_ARBITER_GROUP_GUARD_CHECK(_group)
#define UCS_ARBITER_GROUP_ARBITER_DEFINE
#define UCS_ARBITER_GROUP_ARBITER_SET(_group, _arbiter)
#endif
#define UCS_ARBITER_GROUP_ARBITER_CHECK(_group, _arbiter) \
ucs_assertv((_group)->arbiter == (_arbiter), \
"%p == %p", (_group)->arbiter, _group)
typedef ucs_arbiter_cb_result_t (*ucs_arbiter_callback_t)(ucs_arbiter_t *arbiter,
ucs_arbiter_group_t *group,
ucs_arbiter_elem_t *elem,
void *arg);
struct ucs_arbiter {
ucs_list_link_t list;
};
struct ucs_arbiter_group {
ucs_arbiter_elem_t *tail;
UCS_ARBITER_GROUP_GUARD_DEFINE;
UCS_ARBITER_GROUP_ARBITER_DEFINE;
};
struct ucs_arbiter_elem {
ucs_list_link_t list;
ucs_arbiter_elem_t *next;
ucs_arbiter_group_t *group;
};
void ucs_arbiter_init(ucs_arbiter_t *arbiter);
void ucs_arbiter_cleanup(ucs_arbiter_t *arbiter);
void ucs_arbiter_group_init(ucs_arbiter_group_t *group);
void ucs_arbiter_group_cleanup(ucs_arbiter_group_t *group);
static inline void ucs_arbiter_elem_init(ucs_arbiter_elem_t *elem)
{
elem->group = NULL;
}
int ucs_arbiter_group_is_scheduled(ucs_arbiter_group_t *group);
void ucs_arbiter_group_push_elem_always(ucs_arbiter_group_t *group,
ucs_arbiter_elem_t *elem);
void ucs_arbiter_group_push_head_elem_always(ucs_arbiter_group_t *group,
ucs_arbiter_elem_t *elem);
void ucs_arbiter_group_purge(ucs_arbiter_t *arbiter, ucs_arbiter_group_t *group,
ucs_arbiter_callback_t cb, void *cb_arg);
size_t ucs_arbiter_group_num_elems(ucs_arbiter_group_t *group);
void ucs_arbiter_dump(ucs_arbiter_t *arbiter, FILE *stream);
void ucs_arbiter_group_schedule_nonempty(ucs_arbiter_t *arbiter,
ucs_arbiter_group_t *group);
void ucs_arbiter_group_desched_nonempty(ucs_arbiter_t *arbiter,
ucs_arbiter_group_t *group);
void ucs_arbiter_dispatch_nonempty(ucs_arbiter_t *arbiter, unsigned per_group,
ucs_arbiter_callback_t cb, void *cb_arg);
static inline int ucs_arbiter_is_empty(ucs_arbiter_t *arbiter)
{
return ucs_list_is_empty(&arbiter->list);
}
static inline ucs_arbiter_elem_t*
ucs_arbiter_group_tail(ucs_arbiter_group_t *group)
{
return group->tail;
}
static inline int ucs_arbiter_group_is_empty(ucs_arbiter_group_t *group)
{
return group->tail == NULL;
}
static inline void ucs_arbiter_group_schedule(ucs_arbiter_t *arbiter,
ucs_arbiter_group_t *group)
{
if (ucs_unlikely(!ucs_arbiter_group_is_empty(group))) {
ucs_arbiter_group_schedule_nonempty(arbiter, group);
}
}
static inline void ucs_arbiter_group_desched(ucs_arbiter_t *arbiter,
ucs_arbiter_group_t *group)
{
if (ucs_unlikely(!ucs_arbiter_group_is_empty(group))) {
ucs_arbiter_group_desched_nonempty(arbiter, group);
}
}
static inline int ucs_arbiter_elem_is_scheduled(ucs_arbiter_elem_t *elem)
{
return elem->group != NULL;
}
static inline void
ucs_arbiter_group_push_elem(ucs_arbiter_group_t *group,
ucs_arbiter_elem_t *elem)
{
if (ucs_arbiter_elem_is_scheduled(elem)) {
return;
}
ucs_arbiter_group_push_elem_always(group, elem);
}
static inline void
ucs_arbiter_group_push_head_elem(ucs_arbiter_group_t *group,
ucs_arbiter_elem_t *elem)
{
if (ucs_arbiter_elem_is_scheduled(elem)) {
return;
}
ucs_arbiter_group_push_head_elem_always(group, elem);
}
static inline void
ucs_arbiter_dispatch(ucs_arbiter_t *arbiter, unsigned per_group,
ucs_arbiter_callback_t cb, void *cb_arg)
{
if (ucs_unlikely(!ucs_arbiter_is_empty(arbiter))) {
ucs_arbiter_dispatch_nonempty(arbiter, per_group, cb, cb_arg);
}
}
static inline int
ucs_arbiter_elem_is_only(ucs_arbiter_elem_t *elem)
{
return elem->next == elem;
}
#endif