blob: c1b8967ad44c6daf1a9b49af7e36663138e090ab [file] [log] [blame]
/*****************************************************************************\
** pmix_utils.h - Various PMIx utility functions
*****************************************************************************
* Copyright (C) 2014-2015 Artem Polyakov. All rights reserved.
* Copyright (C) 2015-2017 Mellanox Technologies. All rights reserved.
* Written by Artem Polyakov <artpol84@gmail.com, artemp@mellanox.com>.
*
* This file is part of Slurm, a resource management program.
* For details, see <https://slurm.schedmd.com/>.
* Please also read the included file: DISCLAIMER.
*
* Slurm is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* In addition, as a special exception, the copyright holders give permission
* to link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two. You must obey the GNU
* General Public License in all respects for all of the code used other than
* OpenSSL. If you modify file(s) with this exception, you may extend this
* exception to your version of the file(s), but you are not obligated to do
* so. If you do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source files in
* the program, then also delete it here.
*
* Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with Slurm; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\*****************************************************************************/
#ifndef PMIXP_UTILS_H
#define PMIXP_UTILS_H
#include "pmixp_common.h"
extern int pmixp_count_digits_base10(uint32_t val);
void pmixp_free_buf(void *x);
int pmixp_usock_create_srv(char *path);
size_t pmixp_read_buf(int fd, void *buf, size_t count, int *shutdown,
bool blocking);
size_t pmixp_write_buf(int fd, void *buf, size_t count, int *shutdown,
bool blocking);
size_t pmixp_writev_buf(int sd, struct iovec *iov, size_t iovcnt,
size_t offset, int *shutdown);
int pmixp_fd_set_nodelay(int fd);
bool pmixp_fd_read_ready(int fd, int *shutdown);
bool pmixp_fd_write_ready(int fd, int *shutdown);
int pmixp_srun_send(slurm_addr_t *addr, uint32_t len, char *data);
int pmixp_stepd_send(const char *nodelist, const char *address,
const char *data, uint32_t len, unsigned int start_delay,
unsigned int retry_cnt, int silent);
int pmixp_p2p_send(const char *nodename, const char *address, const char *data,
uint32_t len, unsigned int start_delay,
unsigned int retry_cnt, int silent);
int pmixp_mkdir(char *path, bool trusted);
/* lightweight pmix list of pointers */
#define PMIXP_LIST_DEBUG 0
#define PMIXP_LIST_VAL(elem) (elem->data)
typedef struct pmixp_list_elem_s {
#ifndef NDEBUG
void *lptr;
#endif
void *data;
struct pmixp_list_elem_s *next, *prev;
} pmixp_list_elem_t;
typedef struct pmixp_list_s {
pmixp_list_elem_t *head, *tail;
size_t count;
} pmixp_list_t;
/* PMIx list of pointers with element reuse */
typedef struct pmixp_rlist_s {
pmixp_list_t list;
pmixp_list_t *src_list;
size_t pre_alloc;
} pmixp_rlist_t;
static inline pmixp_list_elem_t *pmixp_list_elem_new(void)
{
return xmalloc(sizeof(pmixp_list_elem_t));
}
static inline void pmixp_list_elem_free(pmixp_list_elem_t *elem)
{
xfree(elem);
}
static inline bool pmixp_list_empty(pmixp_list_t *l)
{
#if PMIXP_LIST_DEBUG
xassert(l->head && l->tail);
#endif
return !(l->count);
}
static inline size_t pmixp_list_count(pmixp_list_t *l)
{
#if PMIXP_LIST_DEBUG
xassert(l->head && l->tail);
#endif
return l->count;
}
static inline void pmixp_list_init_pre(pmixp_list_t *l,
pmixp_list_elem_t *h,
pmixp_list_elem_t *t)
{
xassert(l && h && t);
l->head = h;
l->tail = t;
l->head->data = NULL;
l->head->next = l->tail;
l->head->prev = NULL;
l->tail->data = NULL;
l->tail->prev = l->head;
l->tail->next = NULL;
l->count = 0;
}
static inline void pmixp_list_fini_pre(pmixp_list_t *l,
pmixp_list_elem_t **h,
pmixp_list_elem_t **t)
{
/* list supposed to be empty */
xassert(l->head && l->tail);
xassert(l->head->next == l->tail);
xassert(l->head == l->tail->prev);
xassert(!l->count);
*h = l->head;
*t = l->tail;
l->head = NULL;
l->tail = NULL;
l->count = 0;
}
static inline void pmixp_list_init(pmixp_list_t *l)
{
pmixp_list_init_pre(l, pmixp_list_elem_new(), pmixp_list_elem_new());
}
static inline void pmixp_list_fini(pmixp_list_t *l)
{
pmixp_list_elem_t *elem1, *elem2;
pmixp_list_fini_pre(l, &elem1, &elem2);
pmixp_list_elem_free(elem1);
pmixp_list_elem_free(elem2);
}
static inline void pmixp_list_enq(pmixp_list_t *l, pmixp_list_elem_t *elem)
{
#if PMIXP_LIST_DEBUG
xassert(elem);
xassert(l->head && l->tail);
xassert(!l->head->data && !l->tail->data);
xassert(!l->tail->next && !l->head->prev);
#ifndef NDEBUG
elem->lptr = l;
#endif /* NDEBUG */
#endif /* PMIXP_LIST_DEBUG */
/* setup connection to the previous elem */
elem->prev = l->tail->prev;
elem->prev->next = elem;
/* setup connection to the dummy tail elem */
elem->next = l->tail;
l->tail->prev = elem;
/* reduce element count */
l->count++;
}
static inline pmixp_list_elem_t *pmixp_list_deq(pmixp_list_t *l)
{
pmixp_list_elem_t *ret;
#if PMIXP_LIST_DEBUG
xassert(l->head && l->tail);
xassert(!l->head->data && !l->tail->data);
xassert(!l->tail->next && !l->head->prev);
xassert (!pmixp_list_empty(l));
#endif
/* user is responsible to ensure that
* list is not empty */
ret = l->head->next;
#if PMIXP_LIST_DEBUG
xassert(ret->lptr == l);
#endif
/* reconnect the list, removing element */
l->head->next = ret->next;
ret->next->prev = l->head;
/* reduce element count */
l->count--;
return ret;
}
static inline void pmixp_list_push(pmixp_list_t *l, pmixp_list_elem_t *elem)
{
#if PMIXP_LIST_DEBUG
xassert(l->head && l->tail);
xassert(!l->head->data && !l->tail->data);
xassert(!l->tail->next && !l->head->prev);
#ifndef NDEBUG
elem->lptr = l;
#endif
#endif /* PMIXP_LIST_DEBUG */
/* setup connection with ex-first element */
elem->next = l->head->next;
elem->next->prev = elem;
/* setup connection with dummy head element */
l->head->next = elem;
elem->prev = l->head;
/* reduce element count */
l->count++;
}
static inline pmixp_list_elem_t *pmixp_list_pop(pmixp_list_t *l)
{
pmixp_list_elem_t *ret = NULL;
#if PMIXP_LIST_DEBUG
xassert(l->head && l->tail);
xassert(!l->head->data && !l->tail->data);
xassert(!l->tail->next && !l->head->prev);
xassert (!pmixp_list_empty(l));
#endif
/* user is responsible to ensure that
* list is not empty */
ret = l->tail->prev;
#if PMIXP_LIST_DEBUG
xassert(ret->lptr == l);
#endif
l->tail->prev = ret->prev;
ret->prev->next = l->tail;
l->count--;
return ret;
}
static inline pmixp_list_elem_t *pmixp_list_rem(
pmixp_list_t *l, pmixp_list_elem_t *elem)
{
pmixp_list_elem_t *next;
#if PMIXP_LIST_DEBUG
xassert(elem && l);
xassert(l->head && l->tail);
xassert(!l->head->data && !l->tail->data);
xassert(!l->tail->next && !l->head->prev);
xassert(elem->next && elem->prev);
xassert((elem != l->head) && (elem != l->tail));
xassert(elem->lptr == l);
#endif
next = elem->next;
elem->prev->next = elem->next;
elem->next->prev = elem->prev;
/* protect the list */
elem->next = elem->prev = NULL;
l->count--;
return next;
}
static inline pmixp_list_elem_t *pmixp_list_begin(pmixp_list_t *l)
{
#if PMIXP_LIST_DEBUG
xassert(l->head && l->tail);
xassert(!l->head->data && !l->tail->data);
xassert(!l->tail->next && !l->head->prev);
#endif
return l->head->next;
}
static inline pmixp_list_elem_t *pmixp_list_end(pmixp_list_t *l)
{
#if PMIXP_LIST_DEBUG
xassert(l->head && l->tail);
xassert(!l->head->data && !l->tail->data);
xassert(!l->tail->next && !l->head->prev);
#endif
return l->tail;
}
static inline pmixp_list_elem_t *pmixp_list_next(
pmixp_list_t *l, pmixp_list_elem_t *cur)
{
#if PMIXP_LIST_DEBUG
xassert(l->head && l->tail);
xassert(!l->head->data && !l->tail->data);
xassert(!l->tail->next && !l->head->prev);
xassert(cur);
xassert(cur->lptr == l);
#endif
return cur->next;
}
static inline pmixp_list_elem_t *__pmixp_rlist_get_free(
pmixp_list_t *l, size_t pre_alloc)
{
if (pmixp_list_empty(l)) {
/* add l->pre_alloc elements to the source list */
int i;
for (i=0; i<pre_alloc-1; i++) {
pmixp_list_enq(l, pmixp_list_elem_new());
}
}
return pmixp_list_deq(l);
}
static inline void pmixp_rlist_init(
pmixp_rlist_t *l, pmixp_list_t *elem_src, size_t pre_alloc)
{
pmixp_list_elem_t *h, *t;
xassert(l && elem_src && pre_alloc);
l->src_list = elem_src;
l->pre_alloc = pre_alloc;
/* initialize local list */
h = __pmixp_rlist_get_free(elem_src, pre_alloc);
t = __pmixp_rlist_get_free(elem_src, pre_alloc);
xassert(h && t);
pmixp_list_init_pre(&l->list,h, t);
}
static inline void pmixp_rlist_fini(pmixp_rlist_t *l)
{
pmixp_list_elem_t *h, *t;
xassert(l);
pmixp_list_fini_pre(&l->list, &h, &t);
xassert(h && t);
pmixp_list_enq(l->src_list, h);
pmixp_list_enq(l->src_list, t);
}
static inline bool pmixp_rlist_empty(pmixp_rlist_t *l)
{
return pmixp_list_empty(&l->list);
}
static inline size_t pmixp_rlist_count(pmixp_rlist_t *l)
{
return pmixp_list_count(&l->list);
}
static inline void pmixp_rlist_enq(pmixp_rlist_t *l, void *ptr)
{
pmixp_list_elem_t *elem = NULL;
elem = __pmixp_rlist_get_free(l->src_list, l->pre_alloc);
PMIXP_LIST_VAL(elem) = ptr;
pmixp_list_enq(&l->list, elem);
}
static inline void *pmixp_rlist_deq(pmixp_rlist_t *l)
{
pmixp_list_elem_t *elem = NULL;
void *val = NULL;
/* user is responsible to ensure that
* list is not empty
*/
elem = pmixp_list_deq(&l->list);
val = PMIXP_LIST_VAL(elem);
pmixp_list_enq(l->src_list, elem);
return val;
}
static inline void pmixp_rlist_push(pmixp_rlist_t *l, void *ptr)
{
pmixp_list_elem_t *elem = NULL;
elem = __pmixp_rlist_get_free(l->src_list, l->pre_alloc);
PMIXP_LIST_VAL(elem) = ptr;
pmixp_list_push(&l->list, elem);
}
static inline void *pmixp_rlist_pop(pmixp_rlist_t *l)
{
pmixp_list_elem_t *elem = NULL;
void *val = NULL;
#if PMIXP_LIST_DEBUG
xassert(l);
#endif
/* user is responsible to ensure that
* list is not empty
*/
elem = pmixp_list_pop(&l->list);
val = PMIXP_LIST_VAL(elem);
pmixp_list_enq(l->src_list, elem);
return val;
}
static inline pmixp_list_elem_t *pmixp_rlist_begin(pmixp_rlist_t *l)
{
#if PMIXP_LIST_DEBUG
xassert(l);
#endif
return pmixp_list_begin(&l->list);
}
static inline pmixp_list_elem_t *pmixp_rlist_end(pmixp_rlist_t *l)
{
#if PMIXP_LIST_DEBUG
xassert(l);
#endif
return pmixp_list_end(&l->list);
}
static inline pmixp_list_elem_t *pmixp_rlist_next(
pmixp_rlist_t *l, pmixp_list_elem_t *cur)
{
#if PMIXP_LIST_DEBUG
xassert(l && cur);
#endif
return pmixp_list_next(&l->list, cur);
}
static inline pmixp_list_elem_t *pmixp_rlist_rem(
pmixp_rlist_t *l, pmixp_list_elem_t *elem)
{
pmixp_list_elem_t *ret = NULL;
#if PMIXP_LIST_DEBUG
xassert(l && elem);
#endif
ret = pmixp_list_rem(&l->list, elem);
pmixp_list_enq(l->src_list, elem);
return ret;
}
#endif /* PMIXP_UTILS_H*/