/* * Copyright (C) by Argonne National Laboratory * See COPYRIGHT in top-level directory */ #ifndef HYDRA_H_INCLUDED #define HYDRA_H_INCLUDED /* hydra_config.h must come first, otherwise feature macros like _USE_GNU that * were defined by AC_USE_SYSTEM_EXTENSIONS will not be defined yet when mpl.h * indirectly includes features.h. This leads to a mismatch between the * behavior determined by configure and the behavior actually caused by * "#include"ing unistd.h, for example. */ #include "hydra_config.h" #include "mpl.h" #include "uthash.h" extern char *HYD_dbg_prefix; /* C89 headers can be included without a check */ #if defined STDC_HEADERS #include #include #include #include #include #include #else #error "STDC_HEADERS are assumed in the Hydra code" #endif /* STDC_HEADERS */ #if defined NEEDS_POSIX_FOR_SIGACTION #define _POSIX_SOURCE #endif /* NEEDS_POSIX_FOR_SIGACTION */ #if defined HAVE_WINDOWS_H #define WIN32_LEAN_AND_MEAN #include #endif /* HAVE_WINDOWS_H */ #if defined HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if defined HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #if defined HAVE_SYS_TYPES_H #include #endif /* HAVE_SYS_TYPES_H */ #if defined HAVE_SYS_STAT_H #include #endif /* HAVE_SYS_STAT_H */ #if defined HAVE_TIME_H #include #endif /* HAVE_TIME_H */ #if defined HAVE_SYS_TIME_H #include #endif /* HAVE_SYS_TIME_H */ #if defined HAVE_IFADDRS_H #include #endif /* HAVE_IFADDRS_H */ #if defined HAVE_ARPA_INET_H #include #endif /* HAVE_ARPA_INET_H */ #if !defined HAVE_GETTIMEOFDAY #error "hydra requires gettimeofday support" #endif /* HAVE_GETTIMEOFDAY */ #if !defined HAVE_MACRO_VA_ARGS #error "hydra requires VA_ARGS support" #endif /* HAVE_MACRO_VA_ARGS */ #if defined MAXHOSTNAMELEN #define MAX_HOSTNAME_LEN MAXHOSTNAMELEN #else #define MAX_HOSTNAME_LEN 256 #endif /* MAXHOSTNAMELEN */ #define HYDRA_MAX_PATH 4096 /* sockets required headers */ #ifdef HAVE_POLL_H #include #endif /* HAVE_POLL_H */ #ifdef HAVE_FCNTL_H #include #endif /* HAVE_FCNTL_H */ #ifdef HAVE_NETDB_H #include #endif /* HAVE_NETDB_H */ #ifdef HAVE_NETINET_IN_H #include #endif /* HAVE_NETINET_IN_H */ #ifdef HAVE_NETINET_TCP_H #include #endif /* HAVE_NETINET_TCP_H */ #ifdef HAVE_SYS_SOCKET_H #include #endif /* HAVE_SYS_SOCKET_H */ #ifdef HAVE_SIGNAL_H #include #endif /* HAVE_SIGNAL_H */ #define HYD_POLLIN (0x0001) #define HYD_POLLOUT (0x0002) #define HYD_POLLHUP (0x0004) #define HYD_TMPBUF_SIZE (64 * 1024) #define HYD_TMP_STRLEN (16 * 1024) #define HYD_NUM_TMP_STRINGS 1000 #define HYD_DEFAULT_RETRY_COUNT (10) #define HYD_CONNECT_DELAY (10) #define dprintf(...) #ifndef ATTRIBUTE #ifdef HAVE_GCC_ATTRIBUTE #define ATTRIBUTE(a_) __attribute__(a_) #else #define ATTRIBUTE(a_) #endif #endif #define HYD_DRAW_LINE(x) \ { \ int i_; \ for (i_ = 0; i_ < (x); i_++) \ printf("="); \ printf("\n"); \ } #define HYD_CONVERT_FALSE_TO_NULL(x) \ { \ if ((x) == NULL) { \ } \ else if (!strcasecmp((x), "none") || !strcasecmp((x), "no") || \ !strcasecmp((x), "dummy") || !strcasecmp((x), "null") || \ !strcasecmp((x), "nil") || !strcasecmp((x), "false")) { \ MPL_free((x)); \ (x) = NULL; \ } \ } #if defined MANUAL_EXTERN_ENVIRON extern char **environ; #endif /* MANUAL_EXTERN_ENVIRON */ #if defined NEEDS_HSTRERROR_DECL const char *hstrerror(int err); #endif /* NEEDS_HSTRERROR_DECL */ #if defined NEEDS_GETTIMEOFDAY_DECL int gettimeofday(struct timeval *tv, struct timezone *tz); #endif /* NEEDS_GETTIMEOFDAY_DECL */ #if defined NEEDS_GETPGID_DECL pid_t getpgid(pid_t pid); #endif /* NEEDS_GETPGID_DECL */ #if defined NEEDS_KILLPG_DECL int killpg(int pgrp, int sig); #endif /* NEEDS_KILLPG_DECL */ #define HYD_SILENT_ERROR(status) (((status) == HYD_GRACEFUL_ABORT) || ((status) == HYD_TIMED_OUT)) #define HYDRA_NAMESERVER_DEFAULT_PORT 6392 struct HYD_string_stash { char **strlist; int max_count; int cur_count; }; #define HYD_STRING_STASH_INIT(stash) \ do { \ (stash).strlist = NULL; \ (stash).max_count = 0; \ (stash).cur_count = 0; \ } while (0) #define HYD_STRING_STASH(stash, str, status) \ do { \ if ((stash).cur_count >= (stash).max_count - 1) { \ HYDU_REALLOC_OR_JUMP((stash).strlist, char **, \ ((stash).max_count + HYD_NUM_TMP_STRINGS) * sizeof(char *), \ (status)); \ (stash).max_count += HYD_NUM_TMP_STRINGS; \ } \ (stash).strlist[(stash).cur_count++] = (str); \ (stash).strlist[(stash).cur_count] = NULL; \ } while (0) #define HYD_STRING_SPIT(stash, str, status) \ do { \ if ((stash).cur_count == 0) { \ (str) = MPL_strdup(""); \ } \ else { \ (status) = HYDU_str_alloc_and_join((stash).strlist, &(str)); \ HYDU_ERR_POP((status), "unable to join strings\n"); \ HYDU_free_strlist((stash).strlist); \ MPL_free((stash).strlist); \ HYD_STRING_STASH_INIT((stash)); \ } \ } while (0) #define HYD_STRING_STASH_FREE(stash) \ do { \ if ((stash).strlist == NULL) \ break; \ HYDU_free_strlist((stash).strlist); \ MPL_free((stash).strlist); \ (stash).max_count = 0; \ (stash).cur_count = 0; \ } while (0) enum HYD_bool { HYD_FALSE = 0, HYD_TRUE = 1 }; /* fd state */ enum HYD_fd_state { HYD_FD_UNSET = -1, HYD_FD_CLOSED = -2 }; /* Status information */ typedef enum { HYD_SUCCESS = 0, HYD_FAILURE, /* general failure */ /* Silent errors */ HYD_GRACEFUL_ABORT, HYD_TIMED_OUT, /* Regular errors */ HYD_NO_MEM, HYD_SOCK_ERROR, HYD_INVALID_PARAM, HYD_INTERNAL_ERROR } HYD_status; #define HYD_USIZE_UNSET (0) #define HYD_USIZE_SYSTEM (-1) #define HYD_USIZE_INFINITE (-2) #define HYD_GPUS_PER_PROC_UNSET (-1) #define HYD_GPUS_PER_PROC_AUTO (-2) #if defined(NEEDS_GETHOSTNAME_DECL) int gethostname(char *name, size_t len); #endif typedef unsigned short HYD_event_t; /* Argument matching functions */ struct HYD_arg_match_table { const char *arg; HYD_status(*handler_fn) (char *arg, char ***argv_p); void (*help_fn) (void); }; /* Environment information */ struct HYD_env { char *env_name; char *env_value; struct HYD_env *next; }; typedef enum HYD_env_overwrite { HYD_ENV_OVERWRITE_TRUE, HYD_ENV_OVERWRITE_FALSE } HYD_env_overwrite_t; typedef enum { HYD_ENV_PROP_UNSET, HYD_ENV_PROP_ALL, HYD_ENV_PROP_NONE, HYD_ENV_PROP_LIST } HYD_env_prop_t; struct HYD_env_global { struct HYD_env *system; struct HYD_env *user; struct HYD_env *inherited; char *prop; }; /* Executable information */ struct HYD_exec { char *exec[HYD_NUM_TMP_STRINGS]; char *wdir; int proc_count; struct HYD_env *user_env; char *env_prop; int appnum; struct HYD_exec *next; }; /* Process group */ struct HYD_pg { int pgid; struct HYD_proxy *proxy_list; int proxy_count; int pg_process_count; int barrier_count; struct HYD_pg *spawner_pg; /* user-specified node-list */ struct HYD_node *user_node_list; int pg_core_count; /* scratch space for the PM */ void *pg_scratch; struct HYD_pg *next; }; /* Information about the node itself */ struct HYD_node { char *hostname; int core_count; int active_processes; int node_id; /* Username */ char *user; /* Node-specific binding information */ char *local_binding; struct HYD_node *next; }; /* Proxy information */ struct HYD_proxy { struct HYD_node *node; struct HYD_pg *pg; /* Back pointer to the PG */ char **exec_launch_info; int proxy_id; int proxy_process_count; /* Filler processes that we are adding on this proxy */ int filler_processes; struct HYD_exec *exec_list; int *pid; int *exit_status; int control_fd; struct HYD_proxy *next; UT_hash_handle hh; }; /* Global user parameters */ struct HYD_user_global { /* RMK */ char *rmk; /* Launcher */ char *launcher; char *launcher_exec; /* Processor/Memory topology */ char *topolib; char *binding; char *mapping; char *membind; int topo_debug; /* Demux engine */ char *demux; /* Network interface */ char *iface; /* Other random parameters */ int enablex; int debug; int usize; int auto_cleanup; int pmi_port; int skip_launch_node; int gpus_per_proc; struct HYD_env_global global_env; }; #define HYDU_dump_prefix(fp) \ { \ fprintf(fp, "[%s] ", HYD_dbg_prefix ? HYD_dbg_prefix : "unknown"); \ fflush(fp); \ } #define HYDU_dump_noprefix(fp, ...) \ { \ fprintf(fp, __VA_ARGS__); \ fflush(fp); \ } #define HYDU_dump(fp, ...) \ { \ HYDU_dump_prefix(fp); \ HYDU_dump_noprefix(fp, __VA_ARGS__); \ } #if defined HAVE__FUNC__ #define HYDU_FUNC __func__ #elif defined HAVE_CAP__FUNC__ #define HYDU_FUNC __FUNC__ #elif defined HAVE__FUNCTION__ #define HYDU_FUNC __FUNCTION__ #endif #if defined __FILE__ && defined HYDU_FUNC #define HYDU_error_printf(...) \ { \ HYDU_dump_prefix(stderr); \ HYDU_dump_noprefix(stderr, "%s (%s:%d): ", HYDU_FUNC, __FILE__, __LINE__); \ HYDU_dump_noprefix(stderr, __VA_ARGS__); \ } #elif defined __FILE__ #define HYDU_error_printf(...) \ { \ HYDU_dump_prefix(stderr); \ HYDU_dump_noprefix(stderr, "%s (%d): ", __FILE__, __LINE__); \ HYDU_dump_noprefix(stderr, __VA_ARGS__); \ } #else #define HYDU_error_printf(...) \ { \ HYDU_dump_prefix(stderr); \ HYDU_dump_noprefix(stderr, __VA_ARGS__); \ } #endif #define HYDU_ASSERT(x, status) \ { \ if ((x) == 0) { \ HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, \ "assert (%s) failed\n", #x); \ } \ } #define HYDU_IGNORE_TIMEOUT(status) \ { \ if ((status) == HYD_TIMED_OUT) \ (status) = HYD_SUCCESS; \ } #define HYDU_ERR_POP(status, ...) \ { \ if (status && !HYD_SILENT_ERROR(status)) { \ HYDU_error_printf(__VA_ARGS__); \ goto fn_fail; \ } \ else if (HYD_SILENT_ERROR(status)) { \ goto fn_exit; \ } \ } #define HYDU_ERR_SETANDJUMP(status, error, ...) \ { \ status = error; \ HYDU_ERR_POP(status, __VA_ARGS__); \ } #define HYDU_ERR_CHKANDJUMP(status, chk, error, ...) \ { \ if ((chk)) \ HYDU_ERR_SETANDJUMP(status, error, __VA_ARGS__); \ } #if defined ENABLE_WARNINGS #define HYDU_warn_printf HYDU_error_printf #else #define HYDU_warn_printf(...) #endif /* ENABLE_WARNINGS */ /* Disable for now; we might add something here in the future */ #define HYDU_FUNC_ENTER() do {} while (0) #define HYDU_FUNC_EXIT() do {} while (0) /* alloc */ void HYDU_init_user_global(struct HYD_user_global *user_global); void HYDU_finalize_user_global(struct HYD_user_global *user_global); void HYDU_init_global_env(struct HYD_env_global *global_env); void HYDU_finalize_global_env(struct HYD_env_global *global_env); HYD_status HYDU_alloc_node(struct HYD_node **node); void HYDU_free_node_list(struct HYD_node *node_list); void HYDU_init_pg(struct HYD_pg *pg, int pgid); HYD_status HYDU_alloc_pg(struct HYD_pg **pg, int pgid); void HYDU_free_pg_list(struct HYD_pg *pg_list); void HYDU_free_proxy_list(struct HYD_proxy *proxy_list); HYD_status HYDU_alloc_exec(struct HYD_exec **exec); void HYDU_free_exec_list(struct HYD_exec *exec_list); HYD_status HYDU_create_proxy_list(struct HYD_exec *exec_list, struct HYD_node *node_list, struct HYD_pg *pg); HYD_status HYDU_correct_wdir(char **wdir); /* args */ HYD_status HYDU_find_in_path(const char *execname, char **path); HYD_status HYDU_parse_array(char ***argv, struct HYD_arg_match_table *match_table); HYD_status HYDU_set_str(char *arg, char **var, const char *val); HYD_status HYDU_set_int(char *arg, int *var, int val); char *HYDU_getcwd(void); HYD_status HYDU_process_mfile_token(char *token, int newline, struct HYD_node **node_list); char *HYDU_get_abs_wd(const char *wd); HYD_status HYDU_parse_hostfile(const char *hostfile, struct HYD_node **node_list, HYD_status(*process_token) (char *token, int newline, struct HYD_node ** node_list)); char *HYDU_find_full_path(const char *execname); HYD_status HYDU_send_strlist(int fd, char **strlist); /* debug */ HYD_status HYDU_dbg_init(const char *str); void HYDU_dbg_finalize(void); /* env */ HYD_status HYDU_env_to_str(struct HYD_env *env, char **str); HYD_status HYDU_list_inherited_env(struct HYD_env **env_list); struct HYD_env *HYDU_env_list_dup(struct HYD_env *env); HYD_status HYDU_env_create(struct HYD_env **env, const char *env_name, const char *env_value); HYD_status HYDU_env_free(struct HYD_env *env); HYD_status HYDU_env_free_list(struct HYD_env *env); struct HYD_env *HYDU_env_lookup(char *env_name, struct HYD_env *env_list); HYD_status HYDU_append_env_to_list(const char *env_name, const char *env_value, struct HYD_env **env_list); HYD_status HYDU_append_env_str_to_list(const char *str, struct HYD_env **env_list); HYD_status HYDU_putenv(struct HYD_env *env, HYD_env_overwrite_t overwrite); HYD_status HYDU_putenv_list(struct HYD_env *env_list, HYD_env_overwrite_t overwrite); HYD_status HYDU_comma_list_to_env_list(char *str, struct HYD_env **env_list); /* launch */ HYD_status HYDU_create_process(char **client_arg, struct HYD_env *env_list, int *in, int *out, int *err, int *pid, int idx); /* others */ int HYDU_dceil(int x, int y); HYD_status HYDU_add_to_node_list(const char *hostname, int num_procs, struct HYD_node **node_list); void HYDU_delay(unsigned long delay); /* signals */ #ifdef NEEDS_POSIX_FOR_SIGACTION #define _POSIX_SOURCE #endif #include #if defined(USE_SIGNAL) || defined(USE_SIGACTION) #include #else #error no signal choice #endif #ifdef NEEDS_STRSIGNAL_DECL extern char *strsignal(int); #endif HYD_status HYDU_set_signal(int signum, void (*handler) (int)); HYD_status HYDU_set_common_signals(void (*handler) (int)); /* Sock utilities */ enum HYDU_sock_comm_flag { HYDU_SOCK_COMM_NONE = 0, HYDU_SOCK_COMM_MSGWAIT = 1 }; HYD_status HYDU_sock_listen(int *listen_fd, char *port_range, uint16_t * port); /* delay is in microseconds */ HYD_status HYDU_sock_connect(const char *host, uint16_t port, int *fd, int retries, unsigned long delay); HYD_status HYDU_sock_accept(int listen_fd, int *fd); HYD_status HYDU_sock_read(int fd, void *buf, int maxlen, int *recvd, int *closed, enum HYDU_sock_comm_flag flag); HYD_status HYDU_sock_write(int fd, const void *buf, int maxlen, int *sent, int *closed, enum HYDU_sock_comm_flag flag); HYD_status HYDU_sock_set_nonblock(int fd); HYD_status HYDU_sock_set_block(int fd); HYD_status HYDU_sock_forward_stdio(int in, int out, int *closed); void HYDU_sock_finalize(void); HYD_status HYDU_sock_get_iface_ip(char *iface, char **ip); HYD_status HYDU_sock_create_and_listen_portstr(char *iface, char *hostname, char *port_range, char **port_str, HYD_status(*callback) (int fd, HYD_event_t events, void *userp), void *userp); HYD_status HYDU_sock_cloexec(int fd); /* Memory utilities */ #include #define HYDU_MALLOC_OR_JUMP(p, type, size, status) \ { \ (p) = (type) MPL_malloc((size), MPL_MEM_PM); \ if ((size != 0) && ((p) == NULL)) \ HYDU_ERR_SETANDJUMP((status), HYD_NO_MEM, \ "failed to allocate %d bytes\n", \ (int) (size)); \ } #define HYDU_REALLOC_OR_JUMP(p, type, size, status) \ { \ (p) = (type) MPL_realloc((p),(size), MPL_MEM_PM); \ if ((size != 0) && ((p) == NULL)) \ HYDU_ERR_SETANDJUMP((status), HYD_NO_MEM, \ "failed to allocate %d bytes\n", \ (int) (size)); \ } HYD_status HYDU_list_append_strlist(char **exec, char **client_arg); HYD_status HYDU_print_strlist(char **args); void HYDU_free_strlist(char **args); HYD_status HYDU_str_alloc_and_join(char **strlist, char **strjoin); HYD_status HYDU_strsplit(char *str, char **str1, char **str2, char sep); HYD_status HYDU_strdup_list(char *src[], char **dest[]); char *HYDU_size_t_to_str(size_t x); char *HYDU_int_to_str(int x); char *HYDU_int_to_str_pad(int x, int maxlen); #if defined HAVE_HERROR #define HYDU_herror herror #else #define HYDU_herror HYDU_int_to_str #endif /* HAVE_HERROR */ int HYDU_strlist_lastidx(char **strlist); char **HYDU_str_to_strlist(char *str); /*! * @} */ #endif /* HYDRA_H_INCLUDED */