Skip to content

Commit

Permalink
LocalTimeR: dont call localtime_r to avoid __tz_convert deadlock
Browse files Browse the repository at this point in the history
  • Loading branch information
lishanglin authored and VCgege committed Dec 5, 2024
1 parent 44e95d8 commit c24ff3f
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 3 deletions.
81 changes: 81 additions & 0 deletions env/env_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,87 @@ static const std::string kSharedLibExt = ".so";
#endif
#endif

namespace port {

static int is_leap_year(time_t year) {
if (year % 4)
return 0; /* A year not divisible by 4 is not leap. */
else if (year % 100)
return 1; /* If div by 4 and not 100 is surely leap. */
else if (year % 400)
return 0; /* If div by 100 *and* 400 is not leap. */
else
return 1; /* If div by 100 and not by 400 is leap. */
}

static int g_daylight_active = [] {
tzset(); // Now 'timezome' global is populated.
time_t t = time(NULL);
struct tm* aux = localtime(&t); // safe in global cons
return aux->tm_isdst;
}();

void nolocks_localtime(struct tm* tmp, time_t t, time_t tz, int dst) {
const int secs_min = 60;
const int secs_hour = 3600;
const int secs_day = 3600 * 24;

t -= tz; /* Adjust for timezone. */
t += 3600 * dst; /* Adjust for daylight time. */
int days = int(t / secs_day); /* Days passed since epoch. */
int seconds = int(t % secs_day); /* Remaining seconds. */

tmp->tm_isdst = dst;
tmp->tm_hour = seconds / secs_hour;
tmp->tm_min = (seconds % secs_hour) / secs_min;
tmp->tm_sec = (seconds % secs_hour) % secs_min;

/* 1/1/1970 was a Thursday, that is, day 4 from the POV of the tm structure
* where sunday = 0, so to calculate the day of the week we have to add 4
* and take the modulo by 7. */
tmp->tm_wday = (days + 4) % 7;

/* Calculate the current year. */
tmp->tm_year = 1970;
while (1) {
/* Leap years have one day more. */
int days_this_year = 365 + is_leap_year(tmp->tm_year);
if (days_this_year > days) break;
days -= days_this_year;
tmp->tm_year++;
}
tmp->tm_yday = days; /* Number of day of the current year. */
/* We need to calculate in which month and day of the month we are. To do
* so we need to skip days according to how many days there are in each
* month, and adjust for the leap year that has one more day in February. */
int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
mdays[1] += is_leap_year(tmp->tm_year);

tmp->tm_mon = 0;
while (days >= mdays[tmp->tm_mon]) {
days -= mdays[tmp->tm_mon];
tmp->tm_mon++;
}

tmp->tm_mday = days + 1; /* Add 1 since our 'days' is zero-based. */
tmp->tm_year -= 1900; /* Surprisingly tm_year is year-1900. */
}

void nolocks_localtime(struct tm* tmp, time_t t, time_t tz) {
return nolocks_localtime(tmp, t, tz, g_daylight_active);
}

void nolocks_localtime(struct tm* tmp, time_t t) {
return nolocks_localtime(tmp, t, timezone, g_daylight_active);
}

struct tm* LocalTimeR(const time_t* timep, struct tm* result) {
nolocks_localtime(result, *timep);
return result;
}

} // namespace port

namespace {

ThreadStatusUpdater* CreateThreadStatusUpdater() {
Expand Down
4 changes: 1 addition & 3 deletions port/sys_time.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ inline void GetTimeOfDay(TimeVal* tv, struct timezone* tz) {
gettimeofday(tv, tz);
}

inline struct tm* LocalTimeR(const time_t* timep, struct tm* result) {
return localtime_r(timep, result);
}
struct tm* LocalTimeR(const time_t* timep, struct tm* result);

} // namespace port

Expand Down

0 comments on commit c24ff3f

Please sign in to comment.