[FFmpeg-devel] [RFC] avoid non-threadsafe localtime, gmtime

Reimar Döffinger Reimar.Doeffinger
Sat Feb 7 14:18:09 CET 2009


On Sat, Feb 07, 2009 at 01:24:19PM +0100, Michael Niedermayer wrote:
> On Sat, Feb 07, 2009 at 12:02:03PM +0100, Reimar D?ffinger wrote:
> > attached patch would be the first step to get rid of the non-threadsafe
> > localtime and gmtime functions.
> > It should work on all POSIX and current Windows versions.
> > For anything else it would still be a simple hack to add support to
> > fallback to the non-threadsafe functions, only libavformat then would
> > not be thread-safe which keeps the probability of issues quite low.
> 
> fine, though i must add the ifdefs are ugly

If you find that ugly, you'll certainly be jumping with joy at the end
of the email.
Neither localtime_s nor localtime_r are available in MinGW actually.
The MinGW developers claimed that they are not necessary because
localtime is thread-safe (due to use thread-local storage), missing that
that is not enough.
An application might do
> struct tm *now = localtime(time());
> some_lib_func();
> use now

So you have the choice of either forbidding all the applications that
use your library to use localtime in this way (with no way to forbid it)
or you can't use localtime in your library.
I do have a solution (just create a new thread for the sole purpose of
running localtime()), and I even have a patch to do that (attached) but
I am sure nobody will like it.
The other solution is to use localtime_r where available and tell
everyone else they use a broken platform and they use localtime/gmtime in their
applications at their own risk (how to do that "telling" is another
question).

Greetings,
Reimar D?ffinger
-------------- next part --------------
Index: utils.c
===================================================================
--- utils.c	(revision 17031)
+++ utils.c	(working copy)
@@ -2874,6 +2874,53 @@
     return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
 }
 
+#ifdef __MINGW32__
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
+
+struct timeconv_arg {
+   const time_t *timep;
+   struct tm *result;
+   struct tm *(*func)(const time_t *);
+};
+
+static unsigned WINAPI timeconv_thread(void *arg) {
+    struct timeconv_arg *tca = arg;
+    *tca->result = *tca->func(tca->timep);
+    _endthreadex(0);
+    return 0;
+}
+
+static void do_timeconv(struct timeconv_arg *tca) {
+    HANDLE t = (HANDLE)_beginthreadex(NULL, 0, timeconv_thread, &tca, 0, NULL);
+    WaitForSingleObject(t, INFINITE);
+    CloseHandle(t);
+}
+#endif
+
+struct tm *ff_localtime(const time_t *timep, struct tm *result)
+{
+#ifdef __MINGW32__
+    struct timeconv_arg tca = {timep, result, localtime};
+    do_timeconv(&tca);
+    return result;
+#else
+    return localtime_r(timep, result);
+#endif
+}
+
+struct tm *ff_gmtime(const time_t *timep, struct tm *result)
+{
+#ifdef __MINGW32__
+    struct timeconv_arg tca = {timep, result, gmtime};
+    do_timeconv(&tca);
+    return result;
+#else
+    return gmtime_r(timep, result);
+#endif
+}
+
 int64_t parse_date(const char *datestr, int duration)
 {
     const char *p;
@@ -2920,9 +2967,9 @@
          * current year-month-day time */
         if (!q) {
             if (is_utc) {
-                dt = *gmtime(&now);
+                ff_gmtime(&now, &dt);
             } else {
-                dt = *localtime(&now);
+                ff_localtime(&now, &dt);
             }
             dt.tm_hour = dt.tm_min = dt.tm_sec = 0;
         } else {



More information about the ffmpeg-devel mailing list