<'
# Copyright (c) 2011-2015, 2017, 2024, 2026 LAAS/CNRS
# All rights reserved.
#
# Redistribution and use  in source  and binary  forms,  with or without
# modification, are permitted provided that the following conditions are
# met:
#
#   1. Redistributions of  source  code must retain the  above copyright
#      notice and this list of conditions.
#   2. Redistributions in binary form must reproduce the above copyright
#      notice and  this list of  conditions in the  documentation and/or
#      other materials provided with the distribution.
#
#                                      Anthony Mallet on Wed Feb 29 2012
#

args components
lang c
'>
#ifndef H_GENOM_COMPONENT
#define H_GENOM_COMPONENT

#include <sys/time.h>

#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>

#include "activity.h"
#include "exception.h"

#include "component-data.h"		/* must be provided by template */


/* --- context ------------------------------------------------------------- */

struct genom_context_data {
  union { /* points back to component */
<'foreach c $components {'>
    struct genom_<"[$c name]">_component *<"[$c name]">_;
<'}'>
  };

  struct genom_exception_data ex;
};

<'foreach c $components {'>
<'  set comp [$c name]'>

/* <"[--- $comp =========================================================] "> */

/* forward declarations */
struct genom_<"$comp">_component_data;

/* services id */
enum {
<'  foreach s [$c services] {'>
  <"$comp">_<"[$s name]">_SVCID,
<'  }'>
  <"$comp">_NSVC /* total */
};

/* tasks id */
enum {
<'  foreach t [$c tasks] {'>
  <"$comp">_<"[$t name]">_TASKID,
<'  }'>
  <"$comp">_NTASK /* total */
};

/* exec tasks */
struct genom_<"$comp">_exec_task {
  struct genom_context_iface context;
  struct genom_context_data context_data;

  const char *name;
  genom_state_rusage rusage;
  struct genom_<"$comp">_activities activities;

  int started, spawned, runnable, shutdown;
  pthread_mutex_t lock;
  pthread_cond_t sync;
};

/* control task */
struct genom_<"$comp">_ctrl_task {
  struct genom_context_iface context;
  struct genom_context_data context_data;

  union genom_<"$comp">_activity_any activity;
  bool run_map[<"$comp">_NSVC];
  struct timeval wakeup;

  int shutdown;
  pthread_mutex_t lock;
  pthread_cond_t sync;
  void (*signalcb)(struct genom_<"$comp">_component *self);
};

/* component */
struct genom_<"$comp">_component {
  const char *instance;

  /* ids */
<'  if {![catch {$c ids} ids]} {'>
  <"[$ids declarator ids]">;
<'  }'>

  /* ports */
  struct {
<'  if {![llength [$c ports]]} {'>
    uint8_t none;
<'  }'>
<'  foreach p [$c ports] {'>
    <"[[$p type] declarator [$p name]_]">;
<'  }'>
  } ports;

  /* remote services */
  struct {
<'  if {![llength [$c remotes]]} {'>
    uint8_t none;
<'  }'>
<'  foreach r [$c remotes] {'>
  <"[[$r type] declarator [$r name]_]">;
<'  }'>
  } remotes;

  /* exec tasks */
  struct {
<'  if {![llength [$c tasks]]} {'>
    uint8_t none;
<'  }'>
<'  foreach t [$c tasks] {'>
    struct genom_<"$comp">_exec_task <"[$t name]_">;
<'  }'>
  } tasks;

  /* control task */
  struct genom_<"$comp">_ctrl_task control;

  /* mutual exclusion for resource access */
  struct {
    int all;				/* all resources locked */
    void *control;			/* control task codel/service */
<'  foreach t [$c tasks] {'>
    void *task_<"[$t name]">;		/* <"[$t name]"> codel */
<'  }'>

    unsigned int q, qnext;		/* fifo (ticket lock) */
    pthread_mutex_t lock;
    pthread_cond_t sync;
  } resources;

  /* template-specific data */
  struct genom_<"$comp">_component_data mw;
};

#ifdef __cplusplus
extern "C" {
#endif
  void	genom_tinit_<"$comp">_component(struct genom_<"$comp">_component *self);
  void	genom_tfini_<"$comp">_component(struct genom_<"$comp">_component *self);

  /* codels invocation */
<'foreach s [$c services] {'>
  genom_event	genom_<"$comp">_svc_<"[$s name]">_controlcb(
    struct genom_<"$comp">_activity_<"[$s name]"> *,
    struct genom_<"$comp">_component *);
<'}'>
<'foreach t [$c tasks] {'>
  enum genom_activity_status	genom_<"$comp">_<"[$t name]">_invoke(
    union genom_<"$comp">_activity_any *,
    struct genom_<"$comp">_component *);
<'}'>

  /* exec tasks */
<'foreach t [$c tasks] {'>
  void *	genom_<"$comp">_task_<"[$t name]">_loop(void *data);
  void		genom_<"$comp">_task_shutdown(
    struct genom_<"$comp">_component *self);
<'}'>
#ifdef __cplusplus
}
#endif

<'}'>

/* resource access */
#define genom_take_resource(self, wait, set) do {                       \
    pthread_mutex_lock(&(self)->resources.lock);                        \
    unsigned int q = (self)->resources.qnext++;                         \
    while(q != self->resources.q || (wait))                             \
      pthread_cond_wait(&(self)->resources.sync,                        \
                        &(self)->resources.lock);                       \
    set;                                                                \
    (self)->resources.q++;                                              \
    pthread_cond_broadcast(&self->resources.sync);                      \
    pthread_mutex_unlock(&self->resources.lock);                        \
  } while(0)

#define genom_give_resource(self, set) do {                             \
    pthread_mutex_lock(&(self)->resources.lock);                        \
    set;                                                                \
    pthread_cond_broadcast(&self->resources.sync);                      \
    pthread_mutex_unlock(&self->resources.lock);                        \
  } while(0)

#ifdef __cplusplus
extern "C" {
#endif
  /* daemonize */
  int	genom_daemonize(void);
  void	genom_signal_parent(void);

  /* logging functions */
  extern char genom_build_date[];
  void	genom_log_enable(int info, int warn, int debug);
  void	genom_log_info(const char *prefix, const char *format, ...)
    __attribute__ ((format (printf, 2, 3)));
  void	genom_log_warnx(const char *prefix, const char *format, ...)
    __attribute__ ((format (printf, 2, 3)));
  void	genom_log_warn(const char *prefix, const char *format, ...)
    __attribute__ ((format (printf, 2, 3)));
  void	genom_log_debug(const char *prefix, const char *format, ...)
    __attribute__ ((format (printf, 2, 3)));
#ifdef __cplusplus
}
#endif

#endif /* H_GENOM_COMPONENT */
