libamxp  1.4.0
Patterns C Implementation
Collaboration diagram for Signals:

Data Structures

struct  _amxp_signal
 Structure containing the signal information. More...
 

Typedefs

typedef struct _amxp_signal amxp_signal_t
 Structure containing the signal information. More...
 

Functions

int amxp_sigmngr_emit_signal (const amxp_signal_mngr_t *const sig_mngr, const char *name, const amxc_var_t *const data)
 Emits a signal. More...
 
int amxp_sigmngr_deferred_call (amxp_signal_mngr_t *const sig_mngr, amxp_deferred_fn_t fn, const amxc_var_t *const data, void *priv)
 Defers a function call. More...
 
int amxp_sigmngr_enable (amxp_signal_mngr_t *const sig_mngr, bool enable)
 Enables or disables the signal manager. More...
 
int amxp_sigmngr_suspend (amxp_signal_mngr_t *const sig_mngr)
 Suspends the handling of signals for the signal manager. More...
 
int amxp_sigmngr_resume (amxp_signal_mngr_t *const sig_mngr)
 Resumes the handling of signals for the signal manager. More...
 
int amxp_signal_new (amxp_signal_mngr_t *sig_mngr, amxp_signal_t **signal, const char *name)
 Constructor function, creates a new signal. More...
 
int amxp_signal_delete (amxp_signal_t **signal)
 Destructor function, deletes a signal. More...
 
void amxp_signal_trigger (amxp_signal_t *const signal, const amxc_var_t *const data)
 Triggers a signal. More...
 
int amxp_signal_emit (const amxp_signal_t *const signal, const amxc_var_t *const data)
 Emits a signal. More...
 
int amxp_signal_read (void)
 Reads from the amxp signal file descriptor. More...
 
int amxp_signal_fd (void)
 Gets the amxp signal file descriptor. More...
 
int amxp_signal_disconnect_all (amxp_signal_t *const signal)
 Disconnects all slots from the signal. More...
 
const char * amxp_signal_name (const amxp_signal_t *const signal)
 Gets the name of the signal. More...
 
bool amxp_signal_has_slots (const amxp_signal_t *const signal)
 Checks if the signal has slots conencted. More...
 

Detailed Description

When a signal is triggered, all callback functions (slots) that are connected are called immediately. When a signal is emitted, it will be triggered after reading from the amxp signal file descriptor. It is recommended to implement an eventloop.

A signal is a name to which slots (callback functions) can connect.

Typedef Documentation

◆ amxp_signal_t

typedef struct _amxp_signal amxp_signal_t

Structure containing the signal information.

Function Documentation

◆ amxp_sigmngr_deferred_call()

int amxp_sigmngr_deferred_call ( amxp_signal_mngr_t *const  sig_mngr,
amxp_deferred_fn_t  fn,
const amxc_var_t *const  data,
void *  priv 
)

Defers a function call.

Adds a function call to the singal queue. This function will be called at the moment the queue is being handled. Using deferred function calls it is possible to make synchronous functions behave asynchronously.

When sig_mngr is NULL, the function call is added to the queue of global signal manager.

The function will be called when reading the amxp signal file descriptor using function amxp_signal_read.

To be able to use this method it is recommended to implement an eventloop.

Parameters
sig_mngrpointer to the sig_mngr pointer. Will be set to NULL
fnthe deferred function
datathe data that is passed to the function.
privsome pointer to private data
Returns
0 when successful, otherwise an error code

Definition at line 536 of file amxp_signal.c.

539  {
540  int retval = -1;
541  int write_length = 0;
542  amxp_signal_mngr_t* mngr = (sig_mngr == NULL) ? &amxp_sigmngr : sig_mngr;
543 
544  when_null(fn, exit);
545 
547 
548  if(!mngr->suspended) {
549  write_length = write(amxp_sigctrl.sigpipe[1], "S", 1);
550  when_true_status(write_length != 1, exit, amxp_signal_queue_unlock());
551  }
552 
553  retval = amxp_deferred_queue(mngr, fn, data, priv);
554 
556 
557 exit:
558  return retval;
559 }
static int amxp_signal_queue_unlock(void)
Definition: amxp_signal.c:95
static int amxp_signal_queue_lock(void)
Definition: amxp_signal.c:91
static signal_ctrl_t amxp_sigctrl
Definition: amxp_signal.c:88
static int amxp_deferred_queue(amxp_signal_mngr_t *sigmngr, amxp_deferred_fn_t fn, const amxc_var_t *const data, void *priv)
Definition: amxp_signal.c:151
static amxp_signal_mngr_t amxp_sigmngr
Definition: amxp_signal.c:89
Structure containing the signal manager information.
Definition: amxp_signal.h:103
int sigpipe[2]
Definition: amxp_signal.c:72

◆ amxp_sigmngr_emit_signal()

int amxp_sigmngr_emit_signal ( const amxp_signal_mngr_t *const  sig_mngr,
const char *  name,
const amxc_var_t *const  data 
)

Emits a signal.

Searches the signal manager for the given signal and emits the signal. This function is basically the same as calling amxp_sigmngr_find_signal and amxp_signal_emit in sequence.

When sig_mngr is NULL, the signal is searched in the global signal manager.

When no signal is found with the given name, this function fails.

The signal will be triggered when reading the amxp signal file descriptor using function amxp_signal_read.

To be able to use this method it is recommended to implement an eventloop.

Parameters
sig_mngrponter to the sig_mngr pointer. Will be set to NULL
namethe name of the signal
datathe data that is passed to all the slots.
Returns
0 when successful, otherwise an error code

Definition at line 514 of file amxp_signal.c.

516  {
517 
518  int retval = -1;
519  amxp_signal_t* signal = NULL;
520  const amxp_signal_mngr_t* mngr = (sig_mngr == NULL) ? &amxp_sigmngr : sig_mngr;
521  amxc_htable_it_t* hit = NULL;
522 
523  when_null(name, exit);
524  when_true(*name == 0, exit)
525 
526  hit = amxc_htable_get(&mngr->signals, name);
527  when_null(hit, exit);
528 
529  signal = amxc_htable_it_get_data(hit, amxp_signal_t, hit);
530  retval = amxp_signal_emit(signal, data);
531 
532 exit:
533  return retval;
534 }
int amxp_signal_emit(const amxp_signal_t *const signal, const amxc_var_t *const data)
Emits a signal.
Definition: amxp_signal.c:742
amxc_htable_t signals
Definition: amxp_signal.h:104
Structure containing the signal information.
Definition: amxp_signal.h:119

◆ amxp_sigmngr_enable()

int amxp_sigmngr_enable ( amxp_signal_mngr_t *const  sig_mngr,
bool  enable 
)

Enables or disables the signal manager.

When a signal manager is disabled, all emitted signals or triggered signals are discarded, including the signal data.

Parameters
sig_mngrpointer to the signal manager. Use NULL for the global signal manager.
enablewhen true signal emitting and triggering is enabled, when false emitting and triggering of signals is blocked for this signal manager.
Returns
0 when successful, otherwise an error code

Definition at line 561 of file amxp_signal.c.

562  {
563  int retval = 0;
564  amxp_signal_mngr_t* mngr = (sig_mngr == NULL) ? &amxp_sigmngr : sig_mngr;
565 
566  mngr->enabled = enable;
567 
568  return retval;
569 }

◆ amxp_sigmngr_resume()

int amxp_sigmngr_resume ( amxp_signal_mngr_t *const  sig_mngr)

Resumes the handling of signals for the signal manager.

When a signal manager is resumed, all queued signals will be handled by the eventloop.

After resuming a signal manager it will be possible to trigger signals again.

When the signal manager was not suspended this functions returns a none-zero value.

Parameters
sig_mngrpointer to the signal manager. Use NULL for the global signal manager.
Returns
0 when successful, otherwise an error code

Definition at line 595 of file amxp_signal.c.

595  {
596  int retval = -1;
597  int write_length = 0;
598  amxp_signal_mngr_t* mngr = (sig_mngr == NULL) ? &amxp_sigmngr : sig_mngr;
599 
600  when_false(mngr->suspended, exit);
601  mngr->suspended = false;
602 
604 
605  amxc_llist_iterate(it, &mngr->signal_queue) {
606  write_length = write(amxp_sigctrl.sigpipe[1], "S", 1);
607  when_true_status(write_length != 1, exit, amxp_signal_queue_unlock());
608  }
609 
610  amxc_llist_append(&amxp_sigctrl.pending_sigmngrs, &mngr->it);
611 
613 
614  retval = 0;
615 
616 exit:
617  return retval;
618 }
amxc_llist_it_t it
Definition: amxp_signal.h:107
amxc_lqueue_t signal_queue
Definition: amxp_signal.h:105
amxc_llist_t pending_sigmngrs
Definition: amxp_signal.c:75

◆ amxp_sigmngr_suspend()

int amxp_sigmngr_suspend ( amxp_signal_mngr_t *const  sig_mngr)

Suspends the handling of signals for the signal manager.

When a signal manager is suspended, all emitted signals are queued but not handled until the signal manager is resumed with amxp_sigmngr_resume.

When a signal manager is suspended, all triggered signals are dropped including the signal data.

When the signal manager was already suspended this functions returns a none-zero value.

Parameters
sig_mngrpointer to the signal manager. Use NULL for the global signal manager.
Returns
0 when successful, otherwise an error code

Definition at line 571 of file amxp_signal.c.

571  {
572  int retval = -1;
573  char buffer[1];
574  amxp_signal_mngr_t* mngr = (sig_mngr == NULL) ? &amxp_sigmngr : sig_mngr;
575 
576  when_true(mngr->suspended, exit);
577 
579 
580  amxc_llist_iterate(it, &mngr->signal_queue) {
581  when_true_status(read(amxp_sigctrl.sigpipe[0], buffer, 1) == -1, exit, amxp_signal_queue_unlock());
582  }
583 
584  amxc_llist_append(&amxp_sigctrl.sigmngrs, &mngr->it);
585  mngr->suspended = true;
586 
588 
589  retval = 0;
590 
591 exit:
592  return retval;
593 }
amxc_llist_t sigmngrs
Definition: amxp_signal.c:74

◆ amxp_signal_delete()

int amxp_signal_delete ( amxp_signal_t **  signal)

Destructor function, deletes a signal.

All connected slots will be automatically disconnected.

The signal is removed from the signal manager it was added to.

Note
It is not safe to delete a signal from within a slot callback function.
Parameters
signalpointer to the pointer that wil point to the new allocated signal.
Returns
0 when successful, otherwise an error code

Definition at line 669 of file amxp_signal.c.

669  {
670  int retval = -1;
671  when_null(signal, exit);
672  when_null(*signal, exit);
673 
675 
676  if(!(*signal)->triggered) {
677  amxc_htable_it_clean(&(*signal)->hit, amxp_free_signals);
678  } else {
679  (*signal)->mngr = NULL;
680  }
681  *signal = NULL;
682 
684 
685  retval = 0;
686 
687 exit:
688  return retval;
689 }
static void amxp_free_signals(UNUSED const char *key, amxc_htable_it_t *it)
Definition: amxp_signal.c:107

◆ amxp_signal_disconnect_all()

int amxp_signal_disconnect_all ( amxp_signal_t *const  signal)

Disconnects all slots from the signal.

Parameters
signalpointer to the signal structure.
Returns
0 when successful, otherwise an error code

Definition at line 806 of file amxp_signal.c.

806  {
807  int retval = -1;
808  when_null(signal, exit);
809 
810  amxc_llist_clean(&signal->slots, amxp_free_slots);
811  retval = 0;
812 
813 exit:
814  return retval;
815 }
void amxp_free_slots(amxc_llist_it_t *it)
Definition: amxp_signal.c:99
amxc_llist_t slots
Definition: amxp_signal.h:121

◆ amxp_signal_emit()

int amxp_signal_emit ( const amxp_signal_t *const  signal,
const amxc_var_t *const  data 
)

Emits a signal.

The signal will be triggered when reading the amxp signal file descriptor using function amxp_signal_read.

To be able to use this method it is recommended to implement an eventloop.

Parameters
signalpointer to the signal structure.
datathe data that will be passed to all slots.
Returns
0 when successful, otherwise an error code

Definition at line 742 of file amxp_signal.c.

743  {
744  int retval = -1;
745  int write_length = 0;
746  amxp_signal_mngr_t* sig_mngr = NULL;
747  when_null(signal, exit);
748  when_null(signal->mngr, exit);
749  sig_mngr = signal->mngr;
750 
751  when_false(sig_mngr->enabled, exit);
752  when_true(sig_mngr->deleted, exit);
753 
755 
756  if(!sig_mngr->suspended) {
757  write_length = write(amxp_sigctrl.sigpipe[1], "S", 1);
758  when_true_status(write_length != 1, exit, amxp_signal_queue_unlock());
759  }
760 
761  retval = amxp_signal_queue(signal, data);
762 
764 
765 exit:
766  return retval;
767 }
static int amxp_signal_queue(const amxp_signal_t *const signal, const amxc_var_t *const data)
Definition: amxp_signal.c:121
amxp_signal_mngr_t * mngr
Definition: amxp_signal.h:123

◆ amxp_signal_fd()

int amxp_signal_fd ( void  )

Gets the amxp signal file descriptor.

Returns
The amxp signal file descriptor

Definition at line 841 of file amxp_signal.c.

841  {
842  return amxp_sigctrl.sigpipe[0];
843 }

◆ amxp_signal_has_slots()

bool amxp_signal_has_slots ( const amxp_signal_t *const  signal)

Checks if the signal has slots conencted.

Parameters
signalpointer to the signal structure.
Returns
True when at least one slot is connected, false when no slots are connected.

Definition at line 821 of file amxp_signal.c.

821  {
822  bool retval = false;
823 
824  when_null(signal, exit);
825  retval = !amxc_llist_is_empty(&signal->slots);
826  when_false(retval, exit);
827 
828  retval = false;
829  amxc_llist_iterate(it, &signal->slots) {
830  amxp_slot_t* slot = amxc_container_of(it, amxp_slot_t, it);
831  if(!slot->deleted) {
832  retval = true;
833  break;
834  }
835  }
836 
837 exit:
838  return retval;
839 }

◆ amxp_signal_name()

const char* amxp_signal_name ( const amxp_signal_t *const  signal)

Gets the name of the signal.

Parameters
signalpointer to the signal structure.
Returns
The name of the signal

Definition at line 817 of file amxp_signal.c.

817  {
818  return signal ? signal->name : NULL;
819 }
const char * name
Definition: amxp_signal.h:122

◆ amxp_signal_new()

int amxp_signal_new ( amxp_signal_mngr_t sig_mngr,
amxp_signal_t **  signal,
const char *  name 
)

Constructor function, creates a new signal.

Creates a new signal and adds it to the given signal manager. If sig_mngr is NULL, the signal is added to the global signal manager.

Note
This function allocates memory, the free the allocated memory use the destruction function amxp_signal_delete
Parameters
sig_mngrpointer to signal manager where the signal must be added
signalpointer to the pointer that wil point to the new allocated signal
namename of the signal
Returns
0 when successful, otherwise an error code

Definition at line 620 of file amxp_signal.c.

622  {
623  int retval = -1;
624  amxc_htable_it_t* hit = NULL;
625  when_null(signal, exit);
626  when_not_null(*signal, exit);
627  when_null(name, exit);
628  when_true(*name == 0, exit)
629 
630  sig_mngr = (sig_mngr == NULL) ? &amxp_sigmngr : sig_mngr;
631  when_null(sig_mngr->it.llist, exit);
632 
633  hit = amxc_htable_get(&sig_mngr->signals, name);
634  when_not_null(hit, exit);
635 
636  *signal = (amxp_signal_t*) calloc(1, sizeof(amxp_signal_t));
637  when_null(*signal, exit);
638  (*signal)->mngr = sig_mngr;
639 
641 
642  amxc_htable_it_init(&(*signal)->hit);
643  amxc_llist_init(&(*signal)->slots);
644  if(amxc_htable_insert(&sig_mngr->signals, name, &(*signal)->hit) == 0) {
645  const char* n = amxc_htable_it_get_key(&(*signal)->hit);
646  when_null_status(n, exit, amxp_signal_queue_unlock());
647  (*signal)->name = n;
648  amxc_llist_for_each(it, (&amxp_sigctrl.sigall->slots)) {
649  amxp_slot_t* slot = amxc_llist_it_get_data(it, amxp_slot_t, it);
650  if(slot->deleted) {
651  continue;
652  }
653  amxp_slot_connect(sig_mngr,
654  name,
655  slot->expr == NULL ? NULL : slot->expr->expression,
656  slot->fn,
657  slot->priv);
658  }
659 
660  retval = 0;
661  }
662 
664 
665 exit:
666  return retval;
667 }
int amxp_slot_connect(amxp_signal_mngr_t *const sig_mngr, const char *const sig_name, const char *const expression, amxp_slot_fn_t fn, void *const priv)
Connects a slot (function) to a named signal of a signal manager.
Definition: amxp_slot.c:300
char * expression
amxp_slot_fn_t fn
amxp_expr_t * expr
amxp_signal_t * sigall
Definition: amxp_signal.c:73

◆ amxp_signal_read()

int amxp_signal_read ( void  )

Reads from the amxp signal file descriptor.

Each signal that was emitted will be read from the file descriptor and triggered. This is usefull when you want to do a full stack unwind before triggering the slots.

To be able to use this method it is recommended to implement an eventloop.

Returns
0 when successful, otherwise an error code

Definition at line 769 of file amxp_signal.c.

769  {
770  int retval = -1;
771  int read_length = 0;
772  char buffer[1];
773  signal_queue_item_t* item = NULL;
774  amxc_htable_it_t* hit = NULL;
775  amxp_signal_t* signal = NULL;
776 
778 
779  read_length = read(amxp_sigctrl.sigpipe[0], buffer, 1);
780  when_true_status(read_length < 1, exit, amxp_signal_queue_unlock());
781  item = amxp_signal_dequeue();
782  when_null_status(item, exit, amxp_signal_queue_unlock());
783 
785 
786  if(item->sig_name != NULL) {
787  hit = amxc_htable_get(&item->sig_mngr->signals, item->sig_name);
788  signal = amxc_container_of(hit, amxp_signal_t, hit);
789  when_null(signal, exit);
790  amxp_signal_trigger(signal, &item->sig_data);
791  } else if(item->fn != NULL) {
792  item->fn(&item->sig_data, item->priv);
793  }
794 
795  retval = 0;
796 
797 exit:
798  if(item != NULL) {
799  amxc_var_clean(&item->sig_data);
800  free(item->sig_name);
801  free(item);
802  }
803  return retval;
804 }
static signal_queue_item_t * amxp_signal_dequeue(void)
Definition: amxp_signal.c:181
void amxp_signal_trigger(amxp_signal_t *const signal, const amxc_var_t *const data)
Triggers a signal.
Definition: amxp_signal.c:691
amxc_var_t sig_data
Definition: amxp_signal.c:81
amxp_deferred_fn_t fn
Definition: amxp_signal.c:84
amxp_signal_mngr_t * sig_mngr
Definition: amxp_signal.c:83

◆ amxp_signal_trigger()

void amxp_signal_trigger ( amxp_signal_t *const  signal,
const amxc_var_t *const  data 
)

Triggers a signal.

All slots connected to the signal will be called. When a private data pointer was given at the time of the connect, the private data is passed to the slot.

The signal name and the signal data are passed to all the connected slots as well.

Parameters
signalpointer to the signal structure.
datathe data that will be passed to all slots.

Definition at line 691 of file amxp_signal.c.

692  {
693  amxp_signal_mngr_t* sig_mngr = NULL;
694  char* sig_name = NULL;
695  static uint32_t recurse = 0;
696 
697  when_null(signal, exit);
698  when_null(signal->mngr, exit);
699  sig_mngr = signal->mngr;
700  when_false(sig_mngr->enabled, exit);
701  when_true(sig_mngr->deleted, exit);
702  when_true(sig_mngr->suspended, exit);
703 
704  recurse++;
705  sig_name = strdup(signal->name);
706  sig_mngr->triggered = true;
707  signal->triggered = true;
708  amxc_llist_for_each(it, (&signal->slots)) {
709  amxp_slot_t* slot = amxc_llist_it_get_data(it, amxp_slot_t, it);
710  // slots that are marked for deletion should not be called anymore
711  if(slot->deleted) {
712  continue;
713  }
714  // always call the remaining slots (if not marked as deleted), even
715  // if the signal is removed (signal->mngr == NULL)
716  amxp_slot_trigger(slot, sig_name, data);
717 
718  }
719  signal->triggered = false;
720  sig_mngr->triggered = false;
721 
722  amxp_sigmngr_trigger_regexp(sig_mngr, sig_name, data);
723  recurse--;
724 
725  if(recurse == 0) {
726  // it is safe now to clean-up memory
727  // garbage collect all deleted slots or the signal
729  }
730 
731  free(sig_name);
732 
733 exit:
734  if(recurse == 0) {
735  // it is safe now to clean-up memory
736  // garbage collect all deleted slots, signals or the signal manager
738  }
739  return;
740 }
static void amxp_sigmngr_trigger_regexp(amxp_signal_mngr_t *sig_mngr, const char *name, const amxc_var_t *const data)
Definition: amxp_signal.c:243
static void amxp_slot_trigger(const amxp_slot_t *const slot, const char *name, const amxc_var_t *const data)
Definition: amxp_signal.c:230
static void amxp_signal_garbage_collect(amxp_signal_t *signal)
Definition: amxp_signal.c:274
static void amxp_sigmngr_garbage_collect(amxp_signal_mngr_t *sig_mngr)
Definition: amxp_signal.c:292