Skip to content

Commit a67e2c0

Browse files
committed
Issue #26: Lock mutex accurately, the approach wasnt thread safe
1 parent 4f544e9 commit a67e2c0

File tree

4 files changed

+97
-47
lines changed

4 files changed

+97
-47
lines changed

src/pg_probackup.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,11 @@ main(int argc, char *argv[])
202202
/*
203203
* Save main thread's tid. It is used call exit() in case of errors.
204204
*/
205+
#ifdef WIN32
206+
main_tid = GetCurrentThreadId();
207+
#else
205208
main_tid = pthread_self();
209+
#endif
206210

207211
/* Parse subcommands and non-subcommand options */
208212
if (argc > 1)

src/utils/logger.c

Lines changed: 85 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
5050

5151
static void elog_internal(int elevel, bool file_only, const char *fmt, va_list args)
5252
pg_attribute_printf(3, 0);
53+
static void elog_stderr(int elevel, const char *fmt, ...)
54+
pg_attribute_printf(2, 3);
5355

5456
/* Functions to work with log files */
5557
static void open_logfile(FILE **file, const char *filename_format);
@@ -63,8 +65,8 @@ static FILE *log_file = NULL;
6365
static FILE *error_log_file = NULL;
6466

6567
static bool exit_hook_registered = false;
66-
/* Logging to file is in progress */
67-
static bool logging_to_file = false;
68+
/* Logging of the current thread is in progress */
69+
static bool loggin_in_progress = false;
6870

6971
static pthread_mutex_t log_file_mutex = PTHREAD_MUTEX_INITIALIZER;
7072

@@ -111,11 +113,37 @@ write_elevel(FILE *stream, int elevel)
111113
fputs("PANIC: ", stream);
112114
break;
113115
default:
114-
elog(ERROR, "invalid logging level: %d", elevel);
116+
elog_stderr(ERROR, "invalid logging level: %d", elevel);
115117
break;
116118
}
117119
}
118120

121+
/*
122+
* Exit with code if it is an error.
123+
* Check for in_cleanup flag to avoid deadlock in case of ERROR in cleanup
124+
* routines.
125+
*/
126+
static void
127+
exit_if_necessary(int elevel)
128+
{
129+
if (elevel > WARNING && !in_cleanup)
130+
{
131+
/* Interrupt other possible routines */
132+
interrupted = true;
133+
134+
/* If this is not the main thread then don't call exit() */
135+
#ifdef WIN32
136+
if (main_tid != GetCurrentThreadId())
137+
ExitThread(elevel);
138+
#else
139+
if (!pthread_equal(main_tid, pthread_self()))
140+
pthread_exit(NULL);
141+
#endif
142+
else
143+
exit(elevel);
144+
}
145+
}
146+
119147
/*
120148
* Logs to stderr or to log file and exit if ERROR or FATAL.
121149
*
@@ -132,18 +160,19 @@ elog_internal(int elevel, bool file_only, const char *fmt, va_list args)
132160
time_t log_time = (time_t) time(NULL);
133161
char strfbuf[128];
134162

135-
write_to_file = !logging_to_file && elevel >= LOG_LEVEL_FILE &&
163+
write_to_file = elevel >= LOG_LEVEL_FILE && log_path[0] != '\0';
164+
write_to_error_log = elevel >= ERROR && error_log_filename &&
136165
log_path[0] != '\0';
137-
write_to_error_log = !logging_to_file && elevel >= ERROR &&
138-
error_log_filename && log_path[0] != '\0';
139166
write_to_stderr = elevel >= LOG_LEVEL_CONSOLE && !file_only;
140167

141168
/*
142-
* There is no need to lock if this is elog() from upper elog() and
143-
* logging is not initialized.
169+
* There is no need to lock if this is elog() from upper elog().
144170
*/
145-
if (write_to_file || write_to_error_log || write_to_stderr)
171+
if (!loggin_in_progress)
172+
{
146173
pthread_mutex_lock(&log_file_mutex);
174+
loggin_in_progress = true;
175+
}
147176

148177
/* We need copy args only if we need write to error log file */
149178
if (write_to_error_log)
@@ -166,8 +195,6 @@ elog_internal(int elevel, bool file_only, const char *fmt, va_list args)
166195
*/
167196
if (write_to_file)
168197
{
169-
logging_to_file = true;
170-
171198
if (log_file == NULL)
172199
{
173200
if (log_filename == NULL)
@@ -182,8 +209,6 @@ elog_internal(int elevel, bool file_only, const char *fmt, va_list args)
182209
vfprintf(log_file, fmt, args);
183210
fputc('\n', log_file);
184211
fflush(log_file);
185-
186-
logging_to_file = false;
187212
}
188213

189214
/*
@@ -193,8 +218,6 @@ elog_internal(int elevel, bool file_only, const char *fmt, va_list args)
193218
*/
194219
if (write_to_error_log)
195220
{
196-
logging_to_file = true;
197-
198221
if (error_log_file == NULL)
199222
open_logfile(&error_log_file, error_log_filename);
200223

@@ -205,7 +228,6 @@ elog_internal(int elevel, bool file_only, const char *fmt, va_list args)
205228
fputc('\n', error_log_file);
206229
fflush(error_log_file);
207230

208-
logging_to_file = false;
209231
va_end(error_args);
210232
}
211233

@@ -228,25 +250,41 @@ elog_internal(int elevel, bool file_only, const char *fmt, va_list args)
228250
va_end(std_args);
229251
}
230252

231-
if (write_to_file || write_to_error_log || write_to_stderr)
253+
if (loggin_in_progress)
254+
{
232255
pthread_mutex_unlock(&log_file_mutex);
256+
loggin_in_progress = false;
257+
}
258+
259+
exit_if_necessary(elevel);
260+
}
261+
262+
/*
263+
* Log only to stderr. It is called only within elog_internal() when another
264+
* logging already was started.
265+
*/
266+
static void
267+
elog_stderr(int elevel, const char *fmt, ...)
268+
{
269+
va_list args;
233270

234271
/*
235-
* Exit with code if it is an error.
236-
* Check for in_cleanup flag to avoid deadlock in case of ERROR in cleanup
237-
* routines.
272+
* Do not log message if severity level is less than log_level.
273+
* It is the little optimisation to put it here not in elog_internal().
238274
*/
239-
if (elevel > WARNING && !in_cleanup)
240-
{
241-
/* Interrupt other possible routines */
242-
interrupted = true;
275+
if (elevel < LOG_LEVEL_CONSOLE && elevel < ERROR)
276+
return;
243277

244-
/* If this is not the main thread then don't call exit() */
245-
if (!pthread_equal(main_tid, pthread_self()))
246-
pthread_exit(NULL);
247-
else
248-
exit(elevel);
249-
}
278+
va_start(args, fmt);
279+
280+
write_elevel(stderr, elevel);
281+
vfprintf(stderr, fmt, args);
282+
fputc('\n', stderr);
283+
fflush(stderr);
284+
285+
va_end(args);
286+
287+
exit_if_necessary(elevel);
250288
}
251289

252290
/*
@@ -417,7 +455,7 @@ logfile_getname(const char *format, time_t timestamp)
417455
struct tm *tm = localtime(&timestamp);
418456

419457
if (log_path[0] == '\0')
420-
elog(ERROR, "logging path is not set");
458+
elog_stderr(ERROR, "logging path is not set");
421459

422460
filename = (char *) palloc(MAXPGPATH);
423461

@@ -427,7 +465,7 @@ logfile_getname(const char *format, time_t timestamp)
427465

428466
/* Treat log_filename as a strftime pattern */
429467
if (strftime(filename + len, MAXPGPATH - len, format, tm) <= 0)
430-
elog(ERROR, "strftime(%s) failed: %s", format, strerror(errno));
468+
elog_stderr(ERROR, "strftime(%s) failed: %s", format, strerror(errno));
431469

432470
return filename;
433471
}
@@ -453,8 +491,8 @@ logfile_open(const char *filename, const char *mode)
453491
{
454492
int save_errno = errno;
455493

456-
elog(FATAL, "could not open log file \"%s\": %s",
457-
filename, strerror(errno));
494+
elog_stderr(FATAL, "could not open log file \"%s\": %s",
495+
filename, strerror(errno));
458496
errno = save_errno;
459497
}
460498

@@ -488,8 +526,8 @@ open_logfile(FILE **file, const char *filename_format)
488526
goto logfile_open;
489527
}
490528
else
491-
elog(ERROR, "cannot stat log file \"%s\": %s",
492-
filename, strerror(errno));
529+
elog_stderr(ERROR, "cannot stat log file \"%s\": %s",
530+
filename, strerror(errno));
493531
}
494532
/* Found log file "filename" */
495533
logfile_exists = true;
@@ -505,35 +543,35 @@ open_logfile(FILE **file, const char *filename_format)
505543
if (stat(control, &control_st) == -1)
506544
{
507545
if (errno != ENOENT)
508-
elog(ERROR, "cannot stat rotation file \"%s\": %s",
509-
control, strerror(errno));
546+
elog_stderr(ERROR, "cannot stat rotation file \"%s\": %s",
547+
control, strerror(errno));
510548
}
511549
else
512550
{
513551
char buf[1024];
514552

515553
control_file = fopen(control, "r");
516554
if (control_file == NULL)
517-
elog(ERROR, "cannot open rotation file \"%s\": %s",
518-
control, strerror(errno));
555+
elog_stderr(ERROR, "cannot open rotation file \"%s\": %s",
556+
control, strerror(errno));
519557

520558
if (fgets(buf, lengthof(buf), control_file))
521559
{
522560
time_t creation_time;
523561

524562
if (!parse_int64(buf, (int64 *) &creation_time, 0))
525-
elog(ERROR, "rotation file \"%s\" has wrong "
526-
"creation timestamp \"%s\"",
527-
control, buf);
563+
elog_stderr(ERROR, "rotation file \"%s\" has wrong "
564+
"creation timestamp \"%s\"",
565+
control, buf);
528566
/* Parsed creation time */
529567

530568
rotation_requested = (cur_time - creation_time) >
531569
/* convert to seconds */
532570
log_rotation_age * 60;
533571
}
534572
else
535-
elog(ERROR, "cannot read creation timestamp from "
536-
"rotation file \"%s\"", control);
573+
elog_stderr(ERROR, "cannot read creation timestamp from "
574+
"rotation file \"%s\"", control);
537575

538576
fclose(control_file);
539577
}
@@ -560,8 +598,8 @@ open_logfile(FILE **file, const char *filename_format)
560598

561599
control_file = fopen(control, "w");
562600
if (control_file == NULL)
563-
elog(ERROR, "cannot open rotation file \"%s\": %s",
564-
control, strerror(errno));
601+
elog_stderr(ERROR, "cannot open rotation file \"%s\": %s",
602+
control, strerror(errno));
565603

566604
fprintf(control_file, "%ld", timestamp);
567605

src/utils/pgut.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ static char *password = NULL;
4242
bool prompt_password = true;
4343
bool force_password = false;
4444

45+
#ifdef WIN32
46+
DWORD main_tid = 0;
47+
#else
4548
pthread_t main_tid = 0;
49+
#endif
4650

4751
/* Database connections */
4852
static PGcancel *volatile cancel_conn = NULL;

src/utils/pgut.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,11 @@ extern const char *PROGRAM_URL;
9595
extern const char *PROGRAM_EMAIL;
9696

9797
/* ID of the main thread */
98+
#ifdef WIN32
99+
extern DWORD main_tid;
100+
#else
98101
extern pthread_t main_tid;
102+
#endif
99103

100104
extern void pgut_help(bool details);
101105

0 commit comments

Comments
 (0)