include/fsm.h, src/fsm/*: reworked memory management of the logging system

This commits reworks the way that memory is allocated for the logging system.

We basically use a double-linked list, with the oldest and the latest elements
stored in a static variable. Most recent log entries are added at the latest
position in this structure.

A new function to clear and free a log unit has been implemented, and can be used
at many points. We take care that each log unit is freed at closing time.

Also, fsm docs have been a bit clarified.

Tested with valgrind:

==6161== LEAK SUMMARY:
==6161==    definitely lost: 5,008 bytes in 54 blocks
==6161==    indirectly lost: 16,119 bytes in 672 blocks

We can consider that as a basis for future work, as these leaks are due to external
causes (e.g. libraries).

Signed-off-by: Jean Sirmai <jean@a-lec.org>
Signed-off-by: Adrien Bourmault <neox@a-lec.org>
This commit is contained in:
Jean Sirmai 2024-11-19 22:09:47 +01:00
parent 4c375c5405
commit fcc2dd1c6e
Signed by: jean
GPG Key ID: FB3115C340E057E3
5 changed files with 124 additions and 82 deletions

View File

@ -177,30 +177,26 @@ enum fsm_enum_log_source {
/** /**
* A log unit must include the followings: * A log unit must include the followings:
* *
* @callergraph * @see fsm_log_t
* @see fsm_log_struct
*/ */
typedef struct fsm_log_unit_struct struct fsm_log_unit_t
{ {
long yy_dd_mm; /**< * date of the event reported in the log */ long yy_dd_mm; /**< * date of the event reported in the log */
long usec; /**< * with microseconds precision */ long usec; /**< * with microseconds precision */
char *file_source; /**< * emitter file */ char *file_source; /**< * emitter file */
char *function_source; /**< * emitter function */ char *function_source; /**< * emitter function */
char *string_value; /**< * any event descriptors */ char *string_value; /**< * any event descriptors */
struct fsm_log_unit_struct *prev; /**< * chained list */ struct fsm_log_unit_t *prev; /**< * chained list */
struct fsm_log_unit_struct *next; /**< * chained list */ struct fsm_log_unit_t *next; /**< * chained list */
} };
fsm_log_unit_struct;
/** /**
* Log is a double-chained list. Two links towards the previous and the next unit * Log is a double-chained list. Two links towards the previous and the next unit
* are required to initialize and manage it. * are required to initialize and manage it.
* *
* @callgraph * @see fsm_log_t_unit
* @see fsm_log_struct_unit
* *
* @callergraph
* @see fsm_init_log() * @see fsm_init_log()
* @see fsm_publish_log() * @see fsm_publish_log()
* @see fsm_clear_log() * @see fsm_clear_log()
@ -209,30 +205,31 @@ typedef struct fsm_log_unit_struct
* @see fsm_seek_log() * @see fsm_seek_log()
* @see fsm_remove_log() * @see fsm_remove_log()
*/ */
typedef struct { struct fsm_log_t
fsm_log_unit_struct *first; /**< * required */ {
fsm_log_unit_struct *last; /**< * required */ struct fsm_log_unit_t *oldest; /**< * required */
} struct fsm_log_unit_t *latest; /**< * required */
fsm_log_struct; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void fsm_init_log (fsm_log_struct *jj); void fsm_init_log (struct fsm_log_t *);
void fsm_publish_log (fsm_log_struct jj); void fsm_publish_log (struct fsm_log_t *);
void fsm_clear_log (fsm_log_struct *jj); void fsm_clear_log (struct fsm_log_t *);
void fsm_clear_log_unit (struct fsm_log_unit_t *);
void fsm_add_log_event (fsm_log_struct *jj, void fsm_add_log_event (struct fsm_log_t *gg_logs,
char *file_source, char *file_source,
char *function_source, char *function_source,
char *string_value); char *string_value);
int fsm_get_log_length(fsm_log_struct jj); int fsm_get_log_length(struct fsm_log_t *);
void fsm_seek_log (fsm_log_struct jj, void fsm_seek_log (struct fsm_log_t *gg_logs,
long usec, long usec,
char *file_source, char *file_source,
char *function_source, char *function_source,
char *string_value); char *string_value);
long fsm_remove_log (fsm_log_struct *jj, long fsm_remove_log (struct fsm_log_t *gg_logs,
char *file_source, char *file_source,
char *function_source, char *function_source,
char *string_value); char *string_value);
@ -248,5 +245,3 @@ void fsm_relay_close_log();
void fsm_init (char *initial_message_from_main); void fsm_init (char *initial_message_from_main);
void fsm_close (char *final_message_from_main); void fsm_close (char *final_message_from_main);

View File

@ -39,26 +39,35 @@
* *
* @since 2024-09 * @since 2024-09
* *
* @param *jj * @param *gg_logs
* @param *file_source * @param *file_source
* @param *function_source * @param *function_source
* @param *string_value * @param *string_value
* *
* @returns the removed event date microseconds * @returns the removed event date microseconds
*/ */
long fsm_remove_log (fsm_log_struct *jj, long fsm_remove_log (struct fsm_log_t *gg_logs,
char *file_source, char *file_source,
char *function_source, char *function_source,
char *string_value) char *string_value)
{ {
long usec; // save latest log ref in tmp
fsm_log_unit_struct *tmp = jj->last; struct fsm_log_unit_t *tmp = gg_logs->latest;
if (! tmp) return -1; long usec = tmp->usec;
usec = tmp->usec;
jj->last = tmp->prev; // if there is no log, get out
if (jj->last) jj->last->next = NULL; if (! tmp)
else jj->first = NULL; return 0;
free (tmp);
// remove the log from history
gg_logs->latest = tmp->prev;
// update gg_logs references if needed
if (gg_logs->latest) gg_logs->latest->next = NULL;
else gg_logs->latest = NULL;
// free the unit memory
fsm_clear_log_unit(tmp);
return usec; return usec;
} }
@ -69,12 +78,12 @@ long fsm_remove_log (fsm_log_struct *jj,
* *
* @since 2024-09 * @since 2024-09
* *
* @param *jj * @param *gg_logs
* @returns log length * @returns log length
*/ */
int fsm_get_log_length (fsm_log_struct jj) int fsm_get_log_length (struct fsm_log_t *gg_logs)
{ {
fsm_log_unit_struct *a_unit = jj.first; struct fsm_log_unit_t *a_unit = gg_logs->oldest;
int nb = 0; int nb = 0;
while (a_unit) while (a_unit)
{ {
@ -90,19 +99,19 @@ int fsm_get_log_length (fsm_log_struct jj)
* *
* @since 2024-09 * @since 2024-09
* *
* @param *jj * @param *gg_logs
* @param usec * @param usec
* @param *file_source * @param *file_source
* @param *function_source * @param *function_source
* @param *string_value * @param *string_value
*/ */
void fsm_seek_log (fsm_log_struct jj, void fsm_seek_log (struct fsm_log_t *gg_logs,
long usec, long usec,
char *file_source, char *file_source,
char *function_source, char *function_source,
char *string_value) char *string_value)
{ {
fsm_log_unit_struct *a_unit = jj.first; struct fsm_log_unit_t *a_unit = gg_logs->oldest;
int nb = 0; int nb = 0;
while (a_unit) while (a_unit)
{ {

View File

@ -47,7 +47,7 @@
* *
* Limiting the access to gg_logs helps to avoid uncontrolled operations on it. * Limiting the access to gg_logs helps to avoid uncontrolled operations on it.
*/ */
static fsm_log_struct gg_logs; static struct fsm_log_t gg_logs = { 0 };
/** /**
@ -148,7 +148,7 @@ void fsm_relay_init_log()
*/ */
void fsm_relay_close_log() void fsm_relay_close_log()
{ {
fsm_publish_log (gg_logs); fsm_publish_log (&gg_logs);
fsm_clear_log (&gg_logs); fsm_clear_log (&gg_logs);
} }

View File

@ -45,7 +45,7 @@
static int string_1_size = 40; static int string_1_size = 40;
static int string_2_size = 40; static int string_2_size = 40;
static int string_3_size = 40; static int string_3_size = 50;
/** /**
* Inits the log: a double chained list. * Inits the log: a double chained list.
@ -54,12 +54,12 @@ static int string_3_size = 40;
* *
* @since 2024-09 * @since 2024-09
* *
* @param *jj * @param *gg_logs
*/ */
void fsm_init_log (fsm_log_struct *jj) void fsm_init_log (struct fsm_log_t *gg_logs)
{ {
jj->first = NULL; gg_logs->oldest = NULL;
jj->last = NULL; gg_logs->latest = NULL;
} }
@ -68,22 +68,38 @@ void fsm_init_log (fsm_log_struct *jj)
* *
* @since 2024-09 * @since 2024-09
* *
* @param *jj * @param *gg_logs
*/ */
void fsm_clear_log (fsm_log_struct *jj) void fsm_clear_log (struct fsm_log_t *gg_logs)
{ {
fsm_log_unit_struct *tmp; struct fsm_log_unit_t *tmp;
fsm_log_unit_struct *a_unit = jj->first; struct fsm_log_unit_t *a_unit = gg_logs->oldest;
while(a_unit) while(a_unit)
{ {
tmp = a_unit; tmp = a_unit;
a_unit = a_unit->next; a_unit = a_unit->next;
free (tmp); fsm_clear_log_unit(tmp);
} }
jj->first = NULL; gg_logs->oldest = NULL;
jj->last = NULL; gg_logs->latest = NULL;
} }
/**
* Deletes all the contents of a log unit and takes care
* of freeing it.
*
* @since 2024-11
*
* @param *unit
*/
void fsm_clear_log_unit (struct fsm_log_unit_t *unit)
{
g_free(unit->file_source);
g_free(unit->function_source);
g_free(unit->string_value);
g_free(unit);
}
/** /**
* Adds a log unit (an event) to the log list. * Adds a log unit (an event) to the log list.
@ -94,12 +110,12 @@ void fsm_clear_log (fsm_log_struct *jj)
* *
* @since 2024-09 * @since 2024-09
* *
* @param *jj * @param *gg_logs
* @param *file_source * @param *file_source
* @param *function_source * @param *function_source
* @param *string_value * @param *string_value
*/ */
void fsm_add_log_event (fsm_log_struct *jj, void fsm_add_log_event (struct fsm_log_t *gg_logs,
char *file_source, char *file_source,
char *function_source, char *function_source,
char *string_value) char *string_value)
@ -107,7 +123,7 @@ void fsm_add_log_event (fsm_log_struct *jj,
struct timeval tv; struct timeval tv;
gettimeofday (&tv, NULL); gettimeofday (&tv, NULL);
fsm_log_unit_struct *new_unit = malloc (sizeof(fsm_log_unit_struct)); struct fsm_log_unit_t *new_unit = g_malloc0 (sizeof(struct fsm_log_unit_t));
if (! new_unit) exit (EXIT_FAILURE); if (! new_unit) exit (EXIT_FAILURE);
new_unit->yy_dd_mm = tv.tv_sec; new_unit->yy_dd_mm = tv.tv_sec;
@ -121,13 +137,17 @@ void fsm_add_log_event (fsm_log_struct *jj,
strncpy (new_unit->function_source, function_source, string_2_size - 1); strncpy (new_unit->function_source, function_source, string_2_size - 1);
strncpy (new_unit->string_value, string_value, string_3_size - 1); strncpy (new_unit->string_value, string_value, string_3_size - 1);
new_unit->next = jj->first; // first time we log something (don't touch new_unit->prev)
new_unit->prev = NULL; if (gg_logs->oldest == NULL)
gg_logs->oldest = new_unit; // record the first reference (once)
// not the first time, just update
else {
new_unit->prev = gg_logs->latest;
new_unit->prev->next = new_unit;
}
if (jj->first) jj->first->prev = new_unit; // in any case, update the latest reference
else jj->last = new_unit; gg_logs->latest = new_unit;
jj->first = new_unit;
} }
@ -141,27 +161,43 @@ void fsm_add_log_event (fsm_log_struct *jj,
* *
* @since 2024-09 * @since 2024-09
* *
* @param *jj * @param *gg_logs
*/ */
void fsm_publish_log (fsm_log_struct jj) void fsm_publish_log (struct fsm_log_t *gg_logs)
{ {
fsm_log_unit_struct *a_unit = jj.last; struct fsm_log_unit_t *a_unit = gg_logs->oldest;
char buf [LOG_MAX_LENGTH]; char *timestamp = g_malloc0 (LOG_MAX_LENGTH * sizeof(char));
int nb = 0; int nb = 0;
while (a_unit) while (a_unit)
{ {
strftime(buf, sizeof(buf), "%D %T", localtime(&a_unit->yy_dd_mm)); strftime(timestamp, LOG_MAX_LENGTH * sizeof(char),
g_message ("%s + %-6ld %6d %-28s %-32s %-40s", "%D %T", localtime(&a_unit->yy_dd_mm));
buf,
g_message ("%s + %-6ld %6d %-28s %-32s %-45s",
timestamp,
a_unit->usec, a_unit->usec,
nb, nb,
a_unit->file_source, a_unit->file_source,
a_unit->function_source, a_unit->function_source,
a_unit->string_value); a_unit->string_value);
free (a_unit->string_value);
a_unit = a_unit->prev; a_unit = a_unit->next;
nb ++; nb ++;
} }
g_free(timestamp);
} }
/*
* LEAK SUMMARY:
*
* g_message (+) or printf
* definitely lost: 5,008 bytes in 54 blocks
* indirectly lost: 16,151 bytes in 673 blocks
*
* g_message (-)
* definitely lost: 5,776 bytes in 55 blocks
* indirectly lost: 17,703 bytes in 728 blocks
*/

View File

@ -65,8 +65,10 @@ int main (int argc, char **argv)
fsm_init ("first instruction / first log"); fsm_init ("first instruction / first log");
fsm_add_log (INFO, MAIN, "main", "*app = gtk_application_new()", fsm_add_log (INFO, MAIN, "main",
"*app = gtk_application_new()",
"| 👉️ trigger app initialization"); "| 👉️ trigger app initialization");
app = gtk_application_new ("org.gem-graph", G_APPLICATION_DEFAULT_FLAGS); app = gtk_application_new ("org.gem-graph", G_APPLICATION_DEFAULT_FLAGS);
fsm_add_log (INFO, MAIN, "main", fsm_add_log (INFO, MAIN, "main",