summaryrefslogtreecommitdiff
path: root/src/irmd/reg/name.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/irmd/reg/name.c')
-rw-r--r--src/irmd/reg/name.c516
1 files changed, 222 insertions, 294 deletions
diff --git a/src/irmd/reg/name.c b/src/irmd/reg/name.c
index db9842d1..1ac939a5 100644
--- a/src/irmd/reg/name.c
+++ b/src/irmd/reg/name.c
@@ -1,3 +1,4 @@
+
/*
* Ouroboros - Copyright (C) 2016 - 2024
*
@@ -20,428 +21,355 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#if defined(__linux__) || defined(__CYGWIN__)
-#define _DEFAULT_SOURCE
-#else
#define _POSIX_C_SOURCE 200809L
-#endif
-
-#include "config.h"
-#define OUROBOROS_PREFIX "reg_name"
+#define OUROBOROS_PREFIX "reg/name"
-#include <ouroboros/errno.h>
#include <ouroboros/logs.h>
-#include <ouroboros/time_utils.h>
-#include <ouroboros/pthread.h>
+#include <ouroboros/utils.h>
#include "name.h"
-#include "utils.h"
+#include <assert.h>
+#include <errno.h>
#include <stdlib.h>
-#include <stdbool.h>
#include <string.h>
-#include <signal.h>
-#include <unistd.h>
-#include <limits.h>
-#include <assert.h>
-
-struct reg_name * reg_name_create(const char * name,
- enum pol_balance lb)
-{
- pthread_condattr_t cattr;
- struct reg_name * n;
-
- assert(name != NULL);
- n = malloc(sizeof(*n));
- if (n == NULL)
- goto fail_malloc;
-
- if (pthread_condattr_init(&cattr))
- goto fail_cattr;
-
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
- if (pthread_cond_init(&n->cond, &cattr))
- goto fail_cond;
-
- if (pthread_mutex_init(&n->mtx, NULL))
- goto fail_mutex;
+struct prog_entry {
+ struct list_head next;
+ char ** exec;
+};
- n->name = strdup(name);
- if (n->name == NULL)
- goto fail_name;
+struct proc_entry {
+ struct list_head next;
+ pid_t pid;
+};
- pthread_condattr_destroy(&cattr);
-
- list_head_init(&n->next);
- list_head_init(&n->reg_progs);
- list_head_init(&n->reg_pids);
-
- n->pol_lb = lb;
- n->state = NAME_IDLE;
-
- return n;
+static void __free_prog_entry(struct prog_entry * entry)
+{
+ assert(entry != NULL);
+ assert(entry->exec != NULL);
- fail_name:
- pthread_mutex_destroy(&n->mtx);
- fail_mutex:
- pthread_cond_destroy(&n->cond);
- fail_cond:
- pthread_condattr_destroy(&cattr);
- fail_cattr:
- free(n);
- fail_malloc:
- return NULL;
+ argvfree(entry->exec);
+ free(entry);
}
-static void cancel_reg_name_destroy(void * o)
+struct reg_name * reg_name_create(const struct name_info * info)
{
struct reg_name * name;
- struct list_head * p;
- struct list_head * h;
- name = (struct reg_name *) o;
+ assert(info != NULL);
- pthread_mutex_unlock(&name->mtx);
-
- pthread_cond_destroy(&name->cond);
- pthread_mutex_destroy(&name->mtx);
+ name = malloc(sizeof(*name));
+ if (name == NULL) {
+ log_err("Failed to malloc name.");
+ goto fail_malloc;
+ }
- if (name->name != NULL)
- free(name->name);
+ list_head_init(&name->next);
+ list_head_init(&name->progs);
+ list_head_init(&name->procs);
+ list_head_init(&name->active);
- list_for_each_safe(p, h, &name->reg_pids) {
- struct pid_el * pe = list_entry(p, struct pid_el, next);
- list_del(&pe->next);
- free(pe);
- }
+ name->info = *info;
+ name->n_progs = 0;
+ name->n_procs = 0;
+ name->n_active = 0;
- list_for_each_safe(p, h, &name->reg_progs) {
- struct str_el * se = list_entry(p, struct str_el, next);
- list_del(&se->next);
- free(se->str);
- free(se);
- }
+ return name;
- free(name);
+ fail_malloc:
+ return NULL;
}
void reg_name_destroy(struct reg_name * name)
{
- if (name == NULL)
- return;
-
- pthread_mutex_lock(&name->mtx);
-
- if (name->state == NAME_DESTROY) {
- pthread_mutex_unlock(&name->mtx);
- return;
- }
-
- if (name->state != NAME_FLOW_ACCEPT)
- name->state = NAME_NULL;
- else
- name->state = NAME_DESTROY;
+ assert(name != NULL);
- pthread_cond_broadcast(&name->cond);
+ assert(list_is_empty(&name->next));
- pthread_cleanup_push(cancel_reg_name_destroy, name);
+ assert(name->n_progs == 0);
+ assert(name->n_procs == 0);
+ assert(name->n_active == 0);
- while (name->state != NAME_NULL)
- pthread_cond_wait(&name->cond, &name->mtx);
+ assert(list_is_empty(&name->progs));
+ assert(list_is_empty(&name->procs));
+ assert(list_is_empty(&name->active));
- pthread_cleanup_pop(true);
+ free(name);
}
-static bool reg_name_has_prog(struct reg_name * name,
- const char * prog)
+static struct proc_entry * __reg_name_get_active(const struct reg_name * name,
+ pid_t pid)
{
struct list_head * p;
- list_for_each(p, &name->reg_progs) {
- struct str_el * name = list_entry(p, struct str_el, next);
- if (!strcmp(name->str, prog))
- return true;
- }
-
- return false;
-}
-
-int reg_name_add_prog(struct reg_name * name,
- struct reg_prog * a)
-{
- struct str_el * n;
-
- if (reg_name_has_prog(name, a->prog)) {
- log_warn("Program %s already accepting flows for %s.",
- a->prog, name->name);
- return 0;
- }
-
- if (!(a->flags & BIND_AUTO)) {
- log_dbg("Program %s cannot be auto-instantiated.", a->prog);
- return 0;
- }
-
- n = malloc(sizeof(*n));
- if (n == NULL)
- return -ENOMEM;
+ assert(name != NULL);
+ assert(pid > 0);
- n->str = strdup(a->prog);
- if (n->str == NULL) {
- free(n);
- return -ENOMEM;
+ list_for_each(p, &name->active) {
+ struct proc_entry * entry;
+ entry = list_entry(p, struct proc_entry, next);
+ if (entry->pid == pid)
+ return entry;
}
- list_add(&n->next, &name->reg_progs);
-
- pthread_mutex_lock(&name->mtx);
-
- if (name->state == NAME_IDLE)
- name->state = NAME_AUTO_ACCEPT;
-
- pthread_mutex_unlock(&name->mtx);
-
- return 0;
+ return NULL;
}
-void reg_name_del_prog(struct reg_name * name,
- const char * prog)
+static void __reg_name_del_all_active(struct reg_name * name,
+ pid_t pid)
{
struct list_head * p;
struct list_head * h;
- list_for_each_safe(p, h, &name->reg_progs) {
- struct str_el * se = list_entry(p, struct str_el, next);
- if (strcmp(prog, se->str) == 0) {
- list_del(&se->next);
- free(se->str);
- free(se);
+ list_for_each_safe(p, h, &name->active) {
+ struct proc_entry * entry;
+ entry = list_entry(p, struct proc_entry, next);
+ if (entry->pid == pid) {
+ list_del(&entry->next);
+ free(entry);
+ name->n_active--;
}
}
-
- pthread_mutex_lock(&name->mtx);
-
- if (name->state == NAME_AUTO_ACCEPT && list_is_empty(&name->reg_progs)) {
- name->state = NAME_IDLE;
- pthread_cond_broadcast(&name->cond);
- }
-
- pthread_mutex_unlock(&name->mtx);
}
-char * reg_name_get_prog(struct reg_name * name)
+static struct proc_entry * __reg_name_get_proc(const struct reg_name * name,
+ pid_t pid)
{
- if (!list_is_empty(&name->reg_pids) || list_is_empty(&name->reg_progs))
- return NULL;
+ struct list_head * p;
+
+ assert(name != NULL);
+ assert(pid > 0);
- return list_first_entry(&name->reg_progs, struct str_el, next)->str;
+ list_for_each(p, &name->procs) {
+ struct proc_entry * entry;
+ entry = list_entry(p, struct proc_entry, next);
+ if (entry->pid == pid)
+ return entry;
+ }
+
+ return NULL;
}
-static bool reg_name_has_pid(struct reg_name * name,
- pid_t pid)
+static struct prog_entry * __reg_name_get_prog(const struct reg_name * name,
+ const char * prog)
{
struct list_head * p;
- list_for_each(p, &name->reg_progs) {
- struct pid_el * name = list_entry(p, struct pid_el, next);
- if (name->pid == pid)
- return true;
+ assert(name != NULL);
+ assert(prog != NULL);
+
+ list_for_each(p, &name->progs) {
+ struct prog_entry * entry;
+ entry = list_entry(p, struct prog_entry, next);
+ if (strcmp(entry->exec[0], prog) == 0)
+ return entry;
}
- return false;
+ return NULL;
}
-int reg_name_add_pid(struct reg_name * name,
- pid_t pid)
+int reg_name_add_active(struct reg_name * name,
+ pid_t pid)
{
- struct pid_el * i;
+ struct proc_entry * entry;
- assert(name);
+ assert(name != NULL);
+ assert(pid > 0);
- if (reg_name_has_pid(name, pid)) {
- log_dbg("Process already registered with this name.");
- return -EPERM;
- }
+ assert(__reg_name_get_proc(name, pid) != NULL);
- pthread_mutex_lock(&name->mtx);
+ log_dbg("Process %d accepting flows for %s.", pid, name->info.name);
- if (name->state == NAME_NULL) {
- pthread_mutex_unlock(&name->mtx);
- log_dbg("Tried to add instance in NULL state.");
- return -EPERM;
- }
+ if (__reg_name_get_active(name, pid) != NULL)
+ log_dbg("Process calling accept from multiple threads.");
- i = malloc(sizeof(*i));
- if (i == NULL) {
- pthread_mutex_unlock(&name->mtx);
- return -ENOMEM;
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL) {
+ log_err("Failed to malloc active.");
+ goto fail_malloc;
}
- i->pid = pid;
+ entry->pid = pid;
- /* load balancing policy assigns queue order for this process. */
- switch(name->pol_lb) {
+ switch (name->info.pol_lb) {
case LB_RR: /* Round robin policy. */
- list_add_tail(&i->next, &name->reg_pids);
+ list_add_tail(&entry->next, &name->active);
break;
case LB_SPILL: /* Keep accepting flows on the current process */
- list_add(&i->next, &name->reg_pids);
+ list_add(&entry->next, &name->active);
break;
default:
- free(i);
- assert(false);
- };
-
- if (name->state == NAME_IDLE ||
- name->state == NAME_AUTO_ACCEPT ||
- name->state == NAME_AUTO_EXEC) {
- name->state = NAME_FLOW_ACCEPT;
- pthread_cond_broadcast(&name->cond);
+ goto fail_unreachable;
}
- pthread_mutex_unlock(&name->mtx);
+ name->n_active++;
return 0;
-}
-void reg_name_set_policy(struct reg_name * name,
- enum pol_balance lb)
-{
- name->pol_lb = lb;
+ fail_unreachable:
+ free(entry);
+ assert(false);
+ fail_malloc:
+ return -1;
}
-static void reg_name_check_state(struct reg_name * name)
+void reg_name_del_active(struct reg_name * name,
+ pid_t pid)
{
- assert(name);
+ struct proc_entry * entry;
- if (name->state == NAME_DESTROY) {
- name->state = NAME_NULL;
- pthread_cond_broadcast(&name->cond);
+ entry = __reg_name_get_active(name, pid);
+ if (entry == NULL)
return;
- }
- if (list_is_empty(&name->reg_pids)) {
- if (!list_is_empty(&name->reg_progs))
- name->state = NAME_AUTO_ACCEPT;
- else
- name->state = NAME_IDLE;
- } else {
- name->state = NAME_FLOW_ACCEPT;
- }
+ list_del(&entry->next);
+
+ name->n_active--;
- pthread_cond_broadcast(&name->cond);
+ free(entry);
}
-void reg_name_del_pid_el(struct reg_name * name,
- struct pid_el * p)
+pid_t reg_name_get_active(struct reg_name * name)
{
- assert(name);
- assert(p);
+ assert(name != NULL);
- list_del(&p->next);
- free(p);
+ if (list_is_empty(&name->active))
+ return -1;
- reg_name_check_state(name);
+ return list_first_entry(&name->active, struct proc_entry, next)->pid;
}
-void reg_name_del_pid(struct reg_name * name,
+int reg_name_add_proc(struct reg_name * name,
pid_t pid)
{
- struct list_head * p;
- struct list_head * h;
+ struct proc_entry * entry;
- assert(name);
+ assert(name != NULL);
+ assert(pid > 0);
- if (name == NULL)
- return;
+ assert(__reg_name_get_proc(name, pid) == NULL);
- list_for_each_safe(p, h, &name->reg_pids) {
- struct pid_el * a = list_entry(p, struct pid_el, next);
- if (a->pid == pid) {
- list_del(&a->next);
- free(a);
- }
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL) {
+ log_err("Failed to malloc proc.");
+ goto fail_malloc;
}
- reg_name_check_state(name);
-}
+ entry->pid = pid;
-pid_t reg_name_get_pid(struct reg_name * name)
-{
- if (name == NULL)
- return -1;
+ list_add(&entry->next, &name->procs);
- if (list_is_empty(&name->reg_pids))
- return -1;
+ name->n_procs++;
- return list_first_entry(&name->reg_pids, struct pid_el, next)->pid;
+ return 0;
+
+ fail_malloc:
+ return -1;
}
-enum name_state reg_name_get_state(struct reg_name * name)
+void reg_name_del_proc(struct reg_name * name,
+ pid_t pid)
{
- enum name_state state;
+ struct proc_entry * entry;
- assert(name);
+ assert(name != NULL);
+ assert(pid > 0);
- pthread_mutex_lock(&name->mtx);
+ entry = __reg_name_get_proc(name, pid);
+ if (entry == NULL)
+ return;
+
+ __reg_name_del_all_active(name, pid);
- state = name->state;
+ list_del(&entry->next);
- pthread_mutex_unlock(&name->mtx);
+ free(entry);
- return state;
+ name->n_procs--;
+
+ assert(__reg_name_get_proc(name, pid) == NULL);
}
-int reg_name_set_state(struct reg_name * name,
- enum name_state state)
+bool reg_name_has_proc(const struct reg_name * name,
+ pid_t pid)
+{
+ return __reg_name_get_proc(name, pid) != NULL;
+} char ** exec;
+
+
+int reg_name_add_prog(struct reg_name * name,
+ char ** exec)
{
- assert(state != NAME_DESTROY);
+ struct prog_entry * entry;
+
+ assert(name != NULL);
+ assert(exec != NULL);
+ assert(exec[0] != NULL);
+
+ assert(__reg_name_get_prog(name, exec[0]) == NULL);
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL) {
+ log_err("Failed to malloc prog.");
+ goto fail_malloc;
+ }
+
+ entry->exec = argvdup(exec);
+ if (entry->exec == NULL) {
+ log_err("Failed to argvdup prog.");
+ goto fail_exec;
+ }
- pthread_mutex_lock(&name->mtx);
+ list_add(&entry->next, &name->progs);
- name->state = state;
- pthread_cond_broadcast(&name->cond);
+ log_dbg("Add prog %s to name %s.", exec[0], name->info.name);
- pthread_mutex_unlock(&name->mtx);
+ name->n_progs++;
return 0;
+
+ fail_exec:
+ free(entry);
+ fail_malloc:
+ return -1;
}
-int reg_name_leave_state(struct reg_name * name,
- enum name_state state,
- struct timespec * timeout)
+void reg_name_del_prog(struct reg_name * name,
+ const char * prog)
{
- struct timespec ts;
- struct timespec * abstime = NULL;
- int ret = 0;
+ struct prog_entry * entry;
- assert(name);
- assert(state != NAME_DESTROY);
+ assert(name != NULL);
+ assert(prog != NULL);
- if (timeout != NULL) {
- clock_gettime(PTHREAD_COND_CLOCK, &ts);
- ts_add(&ts, timeout, &ts);
- abstime = &ts;
- }
+ entry = __reg_name_get_prog(name, prog);
+ if (entry == NULL)
+ return;
- pthread_mutex_lock(&name->mtx);
+ list_del(&entry->next);
- pthread_cleanup_push(__cleanup_mutex_unlock, &name->mtx);
+ __free_prog_entry(entry);
- while (name->state == state && ret != -ETIMEDOUT)
- ret = -__timedwait(&name->cond,&name->mtx, abstime);
+ name->n_progs--;
- if (name->state == NAME_DESTROY) {
- ret = -1;
- name->state = NAME_NULL;
- pthread_cond_broadcast(&name->cond);
- }
+ assert(__reg_name_get_prog(name, prog) == NULL);
+}
- pthread_cleanup_pop(true);
+bool reg_name_has_prog(const struct reg_name * name,
+ const char * prog)
+{
+ assert(name != NULL);
+ assert(prog != NULL);
+
+ return __reg_name_get_prog(name, prog) != NULL;
+}
+
+char ** reg_name_get_exec(const struct reg_name * name)
+{
+ if (list_is_empty(&name->progs))
+ return NULL;
- return ret;
+ return list_first_entry(&name->progs, struct prog_entry, next)->exec;
}