Hi,

On Tue, Nov 25, 2008 at 11:57:07AM +0100, Markus Hoenicka wrote:
> > gmtime_r, readdir_r exists on both Linux and Cygwin platforms and
> > according to man mages exists in FreeBSD as well:
> 
> Yes, I've mentioned those as I do have access to them and positively
> know they support the reentrant versions. I'm more concerned about the
> systems that I don't run myself, like OSX, the other *BSDs, Solaris
> and so on.

since all XSI compliant systems are required to provide thread- and
reentrant-safe functions, those functions are fortunately available on
the vast majority of systems.

So if you compile with
 CPPFLAGS="-D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500 -D_REENTRANT 
-D_THREAD_SAFE"
you should get the XS-interface on all noted platforms, as far as I
know.

Of course, there are the occasional oddities here and there, as with all
``modern'' interfaces. For example, under Solaris, if you don't specify
the above flags, you need to at least specify
 CPPFLAGS="-D_POSIX_PTHREAD_SEMANTICS"
to get the standard-conforming versions of some functions, such as
`strtok_r'.

> > However readdir_r is less important because it is quite reasonable
> > to load shared objects from single thread.
> >
> 
> Once again, it is reasonable, but we must not rely on users doing only
> things that we assume as reasonable.

Agreed. I use libdbi for a plugin to collectd[0]. Each plugin is called
from a thread-pool, so using functions with static memory is an absolute
no-go. Especially since it's not that big of a deal, really. In my
experience, switching from `strerror' to `strerror_r' is the biggest
deal, because it's often used in lots of places.

> > Is there other points where non reenterable functions are used?
> 
> To the best of my knowledge, not in libdbi.

I didn't find any more thread-unsafe functions with a really quick
check:
  [EMAIL PROTECTED]:~/libdbi $ egrep -riI 
'\<(asctime|ctermid|ctime|getgrgid|getgrnam|getlogin|getpwnam|getpwuid|gmtime|localtime|rand|readdir|srand|strerror|strtok|tmpnam|ttyname)\>'
 drivers/
  [EMAIL PROTECTED]:~/libdbi $
Dunno if that's all thread-unsafe functions, but it's better than
nothing ;)

> This is a good excuse to make libdbi thread-safe :-)

Please consider the attached patch. It's against what I considered to be
the current CVS revision, but I haven't CVS for quite some time, so
please forgive me if I'm a bit off ;)

I did not remove that ugly `strtok == strtok_r' hack in
src/dbi_result.c, but I added a warning to it. Is that really necessary?

> > For the record I had seen in sqlite (not sqlite3) backend usage of
> > strtok. So it should be thread unsafe.

How does that make it thread-safe?

Regards,
-octo

[0] <http://collectd.org/>
-- 
Florian octo Forster
Hacker in training
GnuPG: 0x91523C3D
http://verplant.org/
Index: configure.in
===================================================================
RCS file: /cvsroot/libdbi/libdbi/configure.in,v
retrieving revision 1.50
diff -p -u -w -r1.50 configure.in
--- configure.in	11 Nov 2008 23:52:03 -0000	1.50
+++ configure.in	25 Nov 2008 19:42:02 -0000
@@ -149,7 +149,7 @@ AC_DEFINE_UNQUOTED(DRIVER_EXT, "$shlib_e
 AC_DEFINE_UNQUOTED(DLSYM_PREFIX, "$dlsym_prefix", [ Specifies a required prefix for symbol names of dynamically loaded modules ])
 
 
-AC_CHECK_FUNCS(strtoll)
+AC_CHECK_FUNCS(strtoll readdir_r gmtime_r)
 AC_REPLACE_FUNCS(atoll timegm)
 AC_CHECK_FUNCS(vasprintf)
 AC_REPLACE_FUNCS(asprintf)
Index: src/dbi_main.c
===================================================================
RCS file: /cvsroot/libdbi/libdbi/src/dbi_main.c,v
retrieving revision 1.87
diff -p -u -w -r1.87 dbi_main.c
--- src/dbi_main.c	11 Nov 2008 23:51:42 -0000	1.87
+++ src/dbi_main.c	25 Nov 2008 19:42:03 -0000
@@ -170,7 +170,27 @@ int dbi_initialize_r(const char *driverd
 		return -1;
 	}
 	else {
-		while ((driver_dirent = readdir(dir)) != NULL) {
+		struct dirent *buffer;
+		size_t buffer_size;
+		int status;
+
+		/* Allocate memory for readdir_r(3). */
+		buffer_size = sizeof (struct dirent)
+			+ pathconf (effective_driverdir, _PC_NAME_MAX) + 1;
+		buffer = (struct dirent *) malloc (buffer_size);
+		if (buffer == NULL)
+			return -1;
+		memset (buffer, 0, buffer_size);
+
+		status = 0;
+		while (42) {
+			driver_dirent = NULL;
+			status = readdir_r (dir, buffer, &driver_dirent);
+			if (status != 0)
+				break;
+			if (driver_dirent == NULL)
+				break;
+
 			driver = NULL;
 			snprintf(fullpath, FILENAME_MAX, "%s%s%s", effective_driverdir, DBI_PATH_SEPARATOR, driver_dirent->d_name);
 			if ((stat(fullpath, &statbuf) == 0) && S_ISREG(statbuf.st_mode) && strrchr(driver_dirent->d_name, '.') && (!strcmp(strrchr(driver_dirent->d_name, '.'), DRIVER_EXT))) {
@@ -194,8 +214,12 @@ int dbi_initialize_r(const char *driverd
 					if (inst->dbi_verbosity) fprintf(stderr, "libdbi: Failed to load driver: %s\n", fullpath);
 				}
 			}
-		}
+		} /* while (42) */
 		closedir(dir);
+		free (buffer);
+
+		if (status != 0)
+			return status;
 	}
 	
 	return num_loaded;
Index: src/dbi_result.c
===================================================================
RCS file: /cvsroot/libdbi/libdbi/src/dbi_result.c,v
retrieving revision 1.48
diff -p -u -w -r1.48 dbi_result.c
--- src/dbi_result.c	19 Apr 2008 16:09:00 -0000	1.48
+++ src/dbi_result.c	25 Nov 2008 19:42:04 -0000
@@ -39,6 +39,7 @@
 #include <dbi/dbi-dev.h>
 
 #ifdef __MINGW32__
+#warning "Using the thread-unsafe strtok function!"
 #define strtok_r(s1,s2,s3) strtok(s1,s2)
 #endif
 
@@ -1442,7 +1450,7 @@ char *dbi_result_get_as_string_copy_idx(
   char *ERROR = "ERROR";
   char *newstring = NULL;
   char *oldstring = NULL;
-  struct tm *utctime;
+  struct tm utctime;
 
   fieldidx--;
 
@@ -1530,8 +1538,8 @@ char *dbi_result_get_as_string_copy_idx(
   case DBI_TYPE_BINARY:
     break; /* return empty string, do not raise an error */
   case DBI_TYPE_DATETIME:
-    utctime = gmtime(&(RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_datetime));
-    snprintf(newstring, 32, "%04d-%02d-%02d %02d:%02d:%02d", utctime->tm_year+1900, utctime->tm_mon+1, utctime->tm_mday, utctime->tm_hour, utctime->tm_min, utctime->tm_sec);
+    gmtime_r(&(RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_datetime), &utctime);
+    snprintf(newstring, 32, "%04d-%02d-%02d %02d:%02d:%02d", utctime.tm_year+1900, utctime.tm_mon+1, utctime.tm_mday, utctime.tm_hour, utctime.tm_min, utctime.tm_sec);
     break;
   default:
     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
Index: src/timegm.c
===================================================================
RCS file: /cvsroot/libdbi/libdbi/src/timegm.c,v
retrieving revision 1.1
diff -p -u -w -r1.1 timegm.c
--- src/timegm.c	13 Jan 2004 21:02:10 -0000	1.1
+++ src/timegm.c	25 Nov 2008 19:42:04 -0000
@@ -30,7 +30,7 @@
 
 time_t timegm(struct tm *tm) {
   time_t temp_ltime;
-  struct tm *temp_gm;
+  struct tm temp_gm;
 
   if (!tm) {
     temp_ltime = 0;
@@ -39,9 +39,9 @@ time_t timegm(struct tm *tm) {
     temp_ltime = mktime(tm);
   }
 
-  temp_gm = gmtime(&temp_ltime);
+  gmtime(&temp_ltime, &temp_gm);
 
-  return (time_t)(temp_ltime + (temp_ltime - mktime(temp_gm)));
+  return (time_t)(temp_ltime + (temp_ltime - mktime(&temp_gm)));
 }
 
 #endif /* HAVE_TIMEGM */

Attachment: signature.asc
Description: Digital signature

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
libdbi-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libdbi-devel

Reply via email to