No thread safety in clock_gettime (hires_ns::prime)
James E. King III
jking@apache.org
Fri Nov 23 16:27:00 GMT 2018
Using 32-bit cygwin that I set up yesterday. I found that a call to
clock_gettime(CLOCK_MONOTONIC, ..) has a one-time initialization that
is not thread-safe. If two threads call this at the same time, they
will race. The results I am seeing are typically that one of the two
callers get a timespec structure with zero values, and no error return
code from the call.
I prepared a small test that exposes this issue. Given it is a race
condition, you have to run the test in a loop for it to happen. I
have attached the Makefile and source code. If you run "make test" it
will expose the issue:
$ make test
cc -c -o cyg_hires_clock_race.o cyg_hires_clock_race.c
cc cyg_hires_clock_race.o -o cyg_hires_clock_race
ERROR: one of the timespec structures was zero:
main thread: tv_sec = 356242 tv_nsec = 376075900
2nd thread: tv_sec = 0 tv_nsec = 0
ERROR: one of the timespec structures was zero:
main thread: tv_sec = 356242 tv_nsec = 519016800
2nd thread: tv_sec = 0 tv_nsec = 0
ERROR: one of the timespec structures was zero:
main thread: tv_sec = 356242 tv_nsec = 734794100
2nd thread: tv_sec = 0 tv_nsec = 0
ERROR: one of the timespec structures was zero:
main thread: tv_sec = 356243 tv_nsec = 463632400
2nd thread: tv_sec = 0 tv_nsec = 0
make: *** [Makefile:6: test] Error 1
Relevant cygwin version information:
Cygwin DLL version info:
DLL version: 2.11.2
DLL epoch: 19
DLL old termios: 5
DLL malloc env: 28
Cygwin conv: 181
API major: 0
API minor: 329
Shared data: 5
DLL identifier: cygwin1
Mount registry: 3
Cygwin registry name: Cygwin
Installations name: Installations
Cygdrive default prefix:
Build date:
Shared id: cygwin1S5
-------------- next part --------------
/*
* Copyright (C) 2018 James E. King III
*
* Exposes a race condition in hires clock initialization
* If two threads call ::clock_gettime(CLOCK_MONOTONIC) they
* will race to perform one-time global initialization.
* During this race it is possible to see the timespec filled
* in by ::clock_gettime can have tv_sec == 0 && tv_nsec == 0
*
* As this is a race you have to run the test in a loop to catch it.
*/
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <time.h>
void *fill_ts(void *vts)
{
struct timespec *pts = (struct timespec *)vts;
assert(!clock_gettime(CLOCK_MONOTONIC, pts));
return NULL;
}
int main()
{
struct timespec main_ts;
struct timespec thread_ts;
pthread_t thr;
assert(!pthread_create(&thr, NULL, &fill_ts, &thread_ts));
(void)fill_ts(&main_ts);
assert(!pthread_join(thr, NULL));
int failed =
(( main_ts.tv_sec == 0 && main_ts.tv_nsec == 0) ||
(thread_ts.tv_sec == 0 && thread_ts.tv_nsec == 0));
if (failed)
{
fprintf(stderr, "ERROR: one of the timespec structures was zero:\n");
fprintf(stderr, "main thread: tv_sec = %10u tv_nsec = %10u\n", main_ts.tv_sec, main_ts.tv_nsec);
fprintf(stderr, " 2nd thread: tv_sec = %10u tv_nsec = %10u\n", thread_ts.tv_sec, thread_ts.tv_nsec);
return 1;
}
return 0;
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Makefile
Type: application/octet-stream
Size: 161 bytes
Desc: not available
URL: <http://cygwin.com/pipermail/cygwin/attachments/20181123/e0514cff/attachment.obj>
-------------- next part --------------
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
More information about the Cygwin
mailing list