Fix #2768 - remove completed timers

This commit is contained in:
Sergey Lyubka 2025-04-11 11:24:10 +01:00
parent 40a2a8822f
commit 0539cf1023
7 changed files with 56 additions and 32 deletions

View File

@ -4017,8 +4017,8 @@ struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
unsigned flags, void (*fn)(void *), void *arg) { unsigned flags, void (*fn)(void *), void *arg) {
struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t)); struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t));
if (t != NULL) { if (t != NULL) {
flags |= MG_TIMER_AUTODELETE; // We have calloc-ed it, so autodelete
mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg); mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg);
t->id = mgr->timerid++;
} }
return t; return t;
} }
@ -9131,11 +9131,9 @@ bool mg_str_to_num(struct mg_str str, int base, void *val, size_t val_len) {
#define MG_TIMER_CALLED 4
void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms, void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms,
unsigned flags, void (*fn)(void *), void *arg) { unsigned flags, void (*fn)(void *), void *arg) {
t->id = 0, t->period_ms = ms, t->expire = 0; t->period_ms = ms, t->expire = 0;
t->flags = flags, t->fn = fn, t->arg = arg, t->next = *head; t->flags = flags, t->fn = fn, t->arg = arg, t->next = *head;
*head = t; *head = t;
} }
@ -9166,6 +9164,12 @@ void mg_timer_poll(struct mg_timer **head, uint64_t now_ms) {
t->fn(t->arg); t->fn(t->arg);
} }
t->flags |= MG_TIMER_CALLED; t->flags |= MG_TIMER_CALLED;
// If this timer is not repeating and marked AUTODELETE, remove it
if (!(t->flags & MG_TIMER_REPEAT) && (t->flags & MG_TIMER_AUTODELETE)) {
mg_timer_free(head, t);
free(t);
}
} }
} }

View File

@ -1020,16 +1020,17 @@ void mg_log_set_fn(mg_pfn_t fn, void *param);
struct mg_timer { struct mg_timer {
unsigned long id; // Timer ID uint64_t period_ms; // Timer period in milliseconds
uint64_t period_ms; // Timer period in milliseconds uint64_t expire; // Expiration timestamp in milliseconds
uint64_t expire; // Expiration timestamp in milliseconds unsigned flags; // Possible flags values below
unsigned flags; // Possible flags values below #define MG_TIMER_ONCE 0 // Call function once
#define MG_TIMER_ONCE 0 // Call function once #define MG_TIMER_REPEAT 1 // Call function periodically
#define MG_TIMER_REPEAT 1 // Call function periodically #define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set
#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set #define MG_TIMER_CALLED 4 // Timer function was called at least once
void (*fn)(void *); // Function to call #define MG_TIMER_AUTODELETE 8 // free() timer when done
void *arg; // Function argument void (*fn)(void *); // Function to call
struct mg_timer *next; // Linkage void *arg; // Function argument
struct mg_timer *next; // Linkage
}; };
void mg_timer_init(struct mg_timer **head, struct mg_timer *timer, void mg_timer_init(struct mg_timer **head, struct mg_timer *timer,
@ -2208,7 +2209,6 @@ struct mg_mgr {
int dnstimeout; // DNS resolve timeout in milliseconds int dnstimeout; // DNS resolve timeout in milliseconds
bool use_dns6; // Use DNS6 server by default, see #1532 bool use_dns6; // Use DNS6 server by default, see #1532
unsigned long nextid; // Next connection ID unsigned long nextid; // Next connection ID
unsigned long timerid; // Next timer ID
void *userdata; // Arbitrary user data pointer void *userdata; // Arbitrary user data pointer
void *tls_ctx; // TLS context shared by all TLS sessions void *tls_ctx; // TLS context shared by all TLS sessions
uint16_t mqtt_id; // MQTT IDs for pub/sub uint16_t mqtt_id; // MQTT IDs for pub/sub

View File

@ -1,7 +1,7 @@
#include "net.h"
#include "dns.h" #include "dns.h"
#include "fmt.h" #include "fmt.h"
#include "log.h" #include "log.h"
#include "net.h"
#include "printf.h" #include "printf.h"
#include "profile.h" #include "profile.h"
#include "timer.h" #include "timer.h"
@ -218,8 +218,8 @@ struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
unsigned flags, void (*fn)(void *), void *arg) { unsigned flags, void (*fn)(void *), void *arg) {
struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t)); struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t));
if (t != NULL) { if (t != NULL) {
flags |= MG_TIMER_AUTODELETE; // We have calloc-ed it, so autodelete
mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg); mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg);
t->id = mgr->timerid++;
} }
return t; return t;
} }

View File

@ -27,7 +27,6 @@ struct mg_mgr {
int dnstimeout; // DNS resolve timeout in milliseconds int dnstimeout; // DNS resolve timeout in milliseconds
bool use_dns6; // Use DNS6 server by default, see #1532 bool use_dns6; // Use DNS6 server by default, see #1532
unsigned long nextid; // Next connection ID unsigned long nextid; // Next connection ID
unsigned long timerid; // Next timer ID
void *userdata; // Arbitrary user data pointer void *userdata; // Arbitrary user data pointer
void *tls_ctx; // TLS context shared by all TLS sessions void *tls_ctx; // TLS context shared by all TLS sessions
uint16_t mqtt_id; // MQTT IDs for pub/sub uint16_t mqtt_id; // MQTT IDs for pub/sub

View File

@ -1,11 +1,9 @@
#include "timer.h"
#include "arch.h" #include "arch.h"
#include "timer.h"
#define MG_TIMER_CALLED 4
void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms, void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms,
unsigned flags, void (*fn)(void *), void *arg) { unsigned flags, void (*fn)(void *), void *arg) {
t->id = 0, t->period_ms = ms, t->expire = 0; t->period_ms = ms, t->expire = 0;
t->flags = flags, t->fn = fn, t->arg = arg, t->next = *head; t->flags = flags, t->fn = fn, t->arg = arg, t->next = *head;
*head = t; *head = t;
} }
@ -36,5 +34,11 @@ void mg_timer_poll(struct mg_timer **head, uint64_t now_ms) {
t->fn(t->arg); t->fn(t->arg);
} }
t->flags |= MG_TIMER_CALLED; t->flags |= MG_TIMER_CALLED;
// If this timer is not repeating and marked AUTODELETE, remove it
if (!(t->flags & MG_TIMER_REPEAT) && (t->flags & MG_TIMER_AUTODELETE)) {
mg_timer_free(head, t);
free(t);
}
} }
} }

View File

@ -3,16 +3,17 @@
#include "arch.h" #include "arch.h"
struct mg_timer { struct mg_timer {
unsigned long id; // Timer ID uint64_t period_ms; // Timer period in milliseconds
uint64_t period_ms; // Timer period in milliseconds uint64_t expire; // Expiration timestamp in milliseconds
uint64_t expire; // Expiration timestamp in milliseconds unsigned flags; // Possible flags values below
unsigned flags; // Possible flags values below #define MG_TIMER_ONCE 0 // Call function once
#define MG_TIMER_ONCE 0 // Call function once #define MG_TIMER_REPEAT 1 // Call function periodically
#define MG_TIMER_REPEAT 1 // Call function periodically #define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set
#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set #define MG_TIMER_CALLED 4 // Timer function was called at least once
void (*fn)(void *); // Function to call #define MG_TIMER_AUTODELETE 8 // free() timer when done
void *arg; // Function argument void (*fn)(void *); // Function to call
struct mg_timer *next; // Linkage void *arg; // Function argument
struct mg_timer *next; // Linkage
}; };
void mg_timer_init(struct mg_timer **head, struct mg_timer *timer, void mg_timer_init(struct mg_timer **head, struct mg_timer *timer,

View File

@ -1960,6 +1960,22 @@ static void test_timer(void) {
ASSERT(mgr.timers == NULL); ASSERT(mgr.timers == NULL);
ASSERT(mgr.conns == NULL); ASSERT(mgr.conns == NULL);
} }
// Test that non-repeating called timers are deleted, see #2768
{
struct mg_mgr mgr;
int arg = 0;
mg_mgr_init(&mgr);
mg_timer_add(&mgr, 0, MG_TIMER_ONCE, f1, &arg);
ASSERT(mgr.timers != NULL);
mg_mgr_poll(&mgr, 10);
ASSERT(arg == 1);
ASSERT(mgr.timers == NULL);
mg_mgr_free(&mgr);
ASSERT(mgr.timers == NULL);
ASSERT(mgr.conns == NULL);
}
} }
static bool sn(const char *fmt, ...) { static bool sn(const char *fmt, ...) {