mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-09-12 01:24:04 +00:00
[Cron] Fix memory leak
This commit is contained in:
+39
-11
@@ -31,6 +31,30 @@
|
||||
|
||||
#include "ccronexpr.h"
|
||||
|
||||
#define CRON_MAX_SECONDS 60
|
||||
#define CRON_MAX_MINUTES 60
|
||||
#define CRON_MAX_HOURS 24
|
||||
#define CRON_MAX_DAYS_OF_WEEK 8
|
||||
#define CRON_MAX_DAYS_OF_MONTH 32
|
||||
#define CRON_MAX_MONTHS 12
|
||||
#define CRON_MAX_YEARS_DIFF 4
|
||||
|
||||
#define CRON_CF_SECOND 0
|
||||
#define CRON_CF_MINUTE 1
|
||||
#define CRON_CF_HOUR_OF_DAY 2
|
||||
#define CRON_CF_DAY_OF_WEEK 3
|
||||
#define CRON_CF_DAY_OF_MONTH 4
|
||||
#define CRON_CF_MONTH 5
|
||||
#define CRON_CF_YEAR 6
|
||||
|
||||
#define CRON_CF_ARR_LEN 7
|
||||
|
||||
|
||||
static const char* const DAYS_ARR[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||
#define CRON_DAYS_ARR_LEN 7
|
||||
static const char* const MONTHS_ARR[] = { "FOO", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||
#define CRON_MONTHS_ARR_LEN 13
|
||||
|
||||
#define CRON_MAX_STR_LEN_TO_SPLIT 256
|
||||
#define CRON_MAX_NUM_TO_SRING 1000000000
|
||||
/* computes number of digits in decimal number */
|
||||
@@ -60,7 +84,7 @@ void cron_free(void* p);
|
||||
|
||||
/* forward declarations for platforms that may need them */
|
||||
/* can be hidden in time.h */
|
||||
#if !defined(_WIN32) && !defined(__AVR__) && !(defined(ESP8266) || defined(ESP32)) && !defined(ANDROID)
|
||||
#if !defined(_WIN32) && !defined(__AVR__) && !defined(ESP8266) && !defined(ESP_PLATFORM) && !defined(ANDROID)
|
||||
struct tm *gmtime_r(const time_t *timep, struct tm *result);
|
||||
time_t timegm(struct tm* __tp);
|
||||
struct tm *localtime_r(const time_t *timep, struct tm *result);
|
||||
@@ -78,15 +102,16 @@ time_t cron_mktime_gm(struct tm* tm) {
|
||||
#elif defined(__AVR__)
|
||||
/* https://www.nongnu.org/avr-libc/user-manual/group__avr__time.html */
|
||||
return mk_gmtime(tm);
|
||||
#elif (defined(ESP8266) || defined(ESP32))
|
||||
#elif defined(ESP8266) || defined(ESP_PLATFORM)
|
||||
/* https://linux.die.net/man/3/timegm */
|
||||
/* http://www.catb.org/esr/time-programming/ */
|
||||
/* portable version of timegm() */
|
||||
time_t ret;
|
||||
char *tz;
|
||||
tz = getenv("TZ");
|
||||
if (tz)
|
||||
tz = strdup(tz);
|
||||
time_t ret = -1;
|
||||
char *tz_orig = NULL;
|
||||
char *tz = NULL;
|
||||
tz_orig = getenv("TZ");
|
||||
if (tz_orig)
|
||||
tz = strdup(tz_orig);
|
||||
setenv("TZ", "UTC+0", 1);
|
||||
tzset();
|
||||
ret = mktime(tm);
|
||||
@@ -257,6 +282,7 @@ static int add_to_field(struct tm* calendar, int field, int val) {
|
||||
calendar->tm_hour = calendar->tm_hour + val;
|
||||
break;
|
||||
case CRON_CF_DAY_OF_WEEK: /* mkgmtime ignores this field */
|
||||
break;
|
||||
case CRON_CF_DAY_OF_MONTH:
|
||||
calendar->tm_mday = calendar->tm_mday + val;
|
||||
break;
|
||||
@@ -496,12 +522,12 @@ static int do_next(cron_expr* expr, struct tm* calendar, unsigned int dot) {
|
||||
if (!resets || !empty_list) {
|
||||
res = -1;
|
||||
}
|
||||
if (resets) {
|
||||
cron_free(resets);
|
||||
}
|
||||
if (empty_list) {
|
||||
cron_free(empty_list);
|
||||
}
|
||||
if (resets) {
|
||||
cron_free(resets);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -624,6 +650,7 @@ static char** split_str(const char* str, char del, size_t* len_out) {
|
||||
int c = str[i];
|
||||
if (del == str[i]) {
|
||||
if (bi > 0) {
|
||||
if (ri >= len) goto return_error;
|
||||
tmp = strdupl(buf, bi);
|
||||
if (!tmp) goto return_error;
|
||||
res[ri++] = tmp;
|
||||
@@ -636,6 +663,7 @@ static char** split_str(const char* str, char del, size_t* len_out) {
|
||||
}
|
||||
/* tail */
|
||||
if (bi > 0) {
|
||||
if (ri >= len) goto return_error;
|
||||
tmp = strdupl(buf, bi);
|
||||
if (!tmp) goto return_error;
|
||||
res[ri++] = tmp;
|
||||
@@ -645,10 +673,10 @@ static char** split_str(const char* str, char del, size_t* len_out) {
|
||||
return res;
|
||||
|
||||
return_error:
|
||||
free_splitted(res, len);
|
||||
if (buf) {
|
||||
cron_free(buf);
|
||||
}
|
||||
free_splitted(res, len);
|
||||
*len_out = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,12 @@ extern "C" {
|
||||
|
||||
#include <stdint.h> /*added for use if uint*_t data types*/
|
||||
|
||||
|
||||
#define CRON_INVALID_INSTANT ((time_t) -1)
|
||||
|
||||
// Define to use local time
|
||||
#define CRON_USE_LOCAL_TIME
|
||||
|
||||
/**
|
||||
* Parsed cron expression
|
||||
*/
|
||||
@@ -90,30 +96,6 @@ time_t cron_prev(cron_expr* expr, time_t date);
|
||||
} /* extern "C"*/
|
||||
#endif
|
||||
|
||||
#define CRON_MAX_SECONDS 60
|
||||
#define CRON_MAX_MINUTES 60
|
||||
#define CRON_MAX_HOURS 24
|
||||
#define CRON_MAX_DAYS_OF_WEEK 8
|
||||
#define CRON_MAX_DAYS_OF_MONTH 32
|
||||
#define CRON_MAX_MONTHS 12
|
||||
#define CRON_MAX_YEARS_DIFF 4
|
||||
|
||||
#define CRON_CF_SECOND 0
|
||||
#define CRON_CF_MINUTE 1
|
||||
#define CRON_CF_HOUR_OF_DAY 2
|
||||
#define CRON_CF_DAY_OF_WEEK 3
|
||||
#define CRON_CF_DAY_OF_MONTH 4
|
||||
#define CRON_CF_MONTH 5
|
||||
#define CRON_CF_YEAR 6
|
||||
|
||||
#define CRON_CF_ARR_LEN 7
|
||||
|
||||
#define CRON_INVALID_INSTANT ((time_t) -1)
|
||||
|
||||
static const char* const DAYS_ARR[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||
#define CRON_DAYS_ARR_LEN 7
|
||||
static const char* const MONTHS_ARR[] = { "FOO", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||
#define CRON_MONTHS_ARR_LEN 13
|
||||
#endif /* CCRONEXPR_H */
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ extends = common
|
||||
board_build.f_cpu = 80000000L
|
||||
build_flags = ${debug_flags.build_flags} ${mqtt_flags.build_flags} -DHTTPCLIENT_1_1_COMPATIBLE=0
|
||||
build_unflags = -DDEBUG_ESP_PORT
|
||||
lib_deps = https://github.com/TD-er/ESPEasySerial.git
|
||||
lib_deps = https://github.com/TD-er/ESPEasySerial.git#v1.0.14
|
||||
lib_ignore = ESP32_ping, ESP32WebServer, IRremoteESP8266, HeatpumpIR, SD(esp8266), SDFS
|
||||
board = esp12e
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ else:
|
||||
"USES_P052", # SenseAir
|
||||
"USES_P056", # SDS011-Dust
|
||||
"USES_P059", # Encoder
|
||||
"USES_P081", # Cron
|
||||
"USES_P082", # GPS
|
||||
"USES_P085", # AcuDC24x
|
||||
"USES_P087", # Serial Proxy
|
||||
|
||||
+44
-34
@@ -1,9 +1,7 @@
|
||||
// #######################################################################################################
|
||||
|
||||
// #################################### Plugin 081: CRON tasks Scheduler ###########################
|
||||
// #######################################################################################################
|
||||
|
||||
// FIXME TD-er: There is some kind of memory leak in this cron plugin.
|
||||
|
||||
#ifdef USES_P081
|
||||
|
||||
@@ -12,7 +10,7 @@
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "ccronexpr.h"
|
||||
#include "ccronexpr.h"
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +28,7 @@ extern "C"
|
||||
|
||||
|
||||
struct P081_data_struct : public PluginTaskData_base {
|
||||
P081_data_struct(const String& expression)
|
||||
explicit P081_data_struct(const String& expression)
|
||||
{
|
||||
const char *error;
|
||||
|
||||
@@ -97,21 +95,23 @@ time_t P081_computeNextCronTime(taskIndex_t taskIndex, time_t last)
|
||||
static_cast<P081_data_struct *>(getPluginTaskData(taskIndex));
|
||||
|
||||
if ((nullptr != P081_data) && P081_data->isInitialized()) {
|
||||
int32_t freeHeapStart = ESP.getFreeHeap();
|
||||
// int32_t freeHeapStart = ESP.getFreeHeap();
|
||||
|
||||
time_t res = P081_data->get_cron_next(last);
|
||||
|
||||
int32_t freeHeapEnd = ESP.getFreeHeap();
|
||||
/*
|
||||
int32_t freeHeapEnd = ESP.getFreeHeap();
|
||||
|
||||
if (freeHeapEnd < freeHeapStart) {
|
||||
String log = F("Cron: Free Heap Decreased: ");
|
||||
log += String(freeHeapStart - freeHeapEnd);
|
||||
log += F(" (");
|
||||
log += freeHeapStart;
|
||||
log += F(" -> ");
|
||||
log += freeHeapEnd;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
if (freeHeapEnd < freeHeapStart) {
|
||||
String log = F("Cron: Free Heap Decreased: ");
|
||||
log += String(freeHeapStart - freeHeapEnd);
|
||||
log += F(" (");
|
||||
log += freeHeapStart;
|
||||
log += F(" -> ");
|
||||
log += freeHeapEnd;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
*/
|
||||
return res;
|
||||
}
|
||||
return CRON_INVALID_INSTANT;
|
||||
@@ -144,6 +144,28 @@ time_t P081_getCurrentTime()
|
||||
return mktime((struct tm *)¤t);
|
||||
}
|
||||
|
||||
void P081_check_or_init(struct EventStruct *event)
|
||||
{
|
||||
if (systemTimePresent()) {
|
||||
const time_t current_time = P081_getCurrentTime();
|
||||
time_t last_exec_time = P081_getCronExecTime(LASTEXECUTION);
|
||||
time_t next_exec_time = P081_getCronExecTime(NEXTEXECUTION);
|
||||
|
||||
// Must check if the values of LASTEXECUTION and NEXTEXECUTION make sense.
|
||||
// These can be invalid values from a reboot, or simply contain uninitialized values.
|
||||
if ((last_exec_time > current_time) || (last_exec_time == CRON_INVALID_INSTANT) || (next_exec_time == CRON_INVALID_INSTANT)) {
|
||||
// Last execution time cannot be correct.
|
||||
last_exec_time = CRON_INVALID_INSTANT;
|
||||
const time_t tmp_next = P081_computeNextCronTime(event->TaskIndex, current_time);
|
||||
|
||||
if ((tmp_next < next_exec_time) || (next_exec_time == CRON_INVALID_INSTANT)) {
|
||||
next_exec_time = tmp_next;
|
||||
}
|
||||
P081_setCronExecTimes(event, CRON_INVALID_INSTANT, next_exec_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean Plugin_081(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
@@ -251,6 +273,7 @@ boolean Plugin_081(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
|
||||
if (P081_data->isInitialized()) {
|
||||
P081_check_or_init(event);
|
||||
success = true;
|
||||
} else {
|
||||
clearPluginTaskData(event->TaskIndex);
|
||||
@@ -277,31 +300,18 @@ boolean Plugin_081(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
// code to be executed once a second. Tasks which do not require fast response can be added here
|
||||
if (systemTimePresent()) {
|
||||
const time_t current_time = P081_getCurrentTime();
|
||||
time_t last_exec_time = P081_getCronExecTime(LASTEXECUTION);
|
||||
time_t next_exec_time = P081_getCronExecTime(NEXTEXECUTION);
|
||||
|
||||
// Must check if the values of LASTEXECUTION and NEXTEXECUTION make sense.
|
||||
// These can be invalid values from a reboot, or simply contain uninitialized values.
|
||||
if ((last_exec_time > current_time) || (last_exec_time == CRON_INVALID_INSTANT) || (next_exec_time == CRON_INVALID_INSTANT)) {
|
||||
// Last execution time cannot be correct.
|
||||
last_exec_time = CRON_INVALID_INSTANT;
|
||||
const time_t tmp_next = P081_computeNextCronTime(event->TaskIndex, current_time);
|
||||
|
||||
if ((tmp_next < next_exec_time) || (next_exec_time == CRON_INVALID_INSTANT)) {
|
||||
next_exec_time = tmp_next;
|
||||
}
|
||||
P081_setCronExecTimes(event, CRON_INVALID_INSTANT, next_exec_time);
|
||||
}
|
||||
P081_check_or_init(event);
|
||||
time_t next_exec_time = P081_getCronExecTime(NEXTEXECUTION);
|
||||
|
||||
if (next_exec_time != CRON_INVALID_INSTANT) {
|
||||
const bool cron_elapsed = (next_exec_time <= current_time);
|
||||
const time_t current_time = P081_getCurrentTime();
|
||||
const bool cron_elapsed = (next_exec_time <= current_time);
|
||||
|
||||
if (cron_elapsed) {
|
||||
addLog(LOG_LEVEL_DEBUG, F("Cron Elapsed"));
|
||||
|
||||
last_exec_time = next_exec_time;
|
||||
next_exec_time = P081_computeNextCronTime(event->TaskIndex, last_exec_time);
|
||||
time_t last_exec_time = next_exec_time;
|
||||
next_exec_time = P081_computeNextCronTime(event->TaskIndex, current_time);
|
||||
P081_setCronExecTimes(event, last_exec_time, next_exec_time);
|
||||
|
||||
addLog(LOG_LEVEL_DEBUG, String(F("Next execution:")) + getDateTimeString(*gmtime(&next_exec_time)));
|
||||
|
||||
Reference in New Issue
Block a user