Hi,

I used the shm_regex functions from lib in one of my own modules and
noticed that it is dead-locking (it hangs in FUTEX_WAIT).
The code hangs in regexec() when trying to acquire the lock. This was
a bit hard to find out as I couldn't reproduce it in a virtual
machine with some test code I wrote. It turns out this only happens if
the machine has more than one physical CPU core.
Reproducable on x86_64 with two CPU cores, glibc 2.3.6 (from Debian
Etch) and glibc 2.11.1 (from Ubuntu Jaunty).
Attached is a patch which does its own locking and thus works around
this problem.

Best regards,
Stefan

-- 
M.Eng. Stefan Keller
CTO (Technischer Leiter)

Phone  +49-30-203899889
Mobile +49-170-4150437
Fax    +49-30-722399150

[email protected]
www.isaco.de

ISACO GmbH
Kurfürstenstr. 79
10787 Berlin
Germany

Amtsgericht Charlottenburg, HRB 112464B
Geschäftsführer: Daniel Frommherz

From 19c32c5bb8b9e369007db99d541793234608d480 Mon Sep 17 00:00:00 2001
From: Stefan Keller <[email protected]>
Date: Tue, 8 Jun 2010 17:26:46 +0200
Subject: [PATCH] work-around libc's regex deadlock

- libc's regexec() deadlocks with multiple cores and shm
- using own per-regex locking works-around this
---
 lib/shm_regex/shm_regex.c |   35 +++++++++++++++++++++++++++--------
 lib/shm_regex/shm_regex.h |   18 +++++++++++++-----
 2 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/lib/shm_regex/shm_regex.c b/lib/shm_regex/shm_regex.c
index 165d535..e28d1c9 100644
--- a/lib/shm_regex/shm_regex.c
+++ b/lib/shm_regex/shm_regex.c
@@ -27,6 +27,8 @@
  * History
  * -------
  *  2009-04-03	Initial version (Miklos)
+ *  2010-04-25  Use own struct with locking to work-around libc locking failure
+ *              on multi-core hw (skeller)
  */
 
 #include <malloc.h>	/* hook prototypes */
@@ -75,32 +77,37 @@ static void shm_free_hook(void *ptr, const void *caller)
 		__free_hook = orig_free_hook; \
 	} while (0)
 
-int shm_regcomp(regex_t *preg, const char *regex, int cflags)
+int shm_regcomp(shm_regex_t *preg, const char *regex, int cflags)
 {
 	malloc_hook_t	*orig_malloc_hook;
 	realloc_hook_t	*orig_realloc_hook;
 	free_hook_t	*orig_free_hook;
 	int		ret;
 
+	if(!lock_init(&preg->lock)) {
+		return REG_EEND;
+	}
 	replace_malloc_hooks();
-	ret = regcomp(preg, regex, cflags);
+	ret = regcomp(&preg->regexp, regex, cflags);
 	restore_malloc_hooks();
 
+	if(ret) lock_destroy(&preg->lock);
+
 	return ret;
 }
 
-void shm_regfree(regex_t *preg)
+void shm_regfree(shm_regex_t *preg)
 {
 	malloc_hook_t	*orig_malloc_hook;
 	realloc_hook_t	*orig_realloc_hook;
 	free_hook_t	*orig_free_hook;
-
+	lock_destroy(&preg->lock);
 	replace_malloc_hooks();
-	regfree(preg);
+	regfree(&preg->regexp);
 	restore_malloc_hooks();
 }
 
-int shm_regexec(const regex_t *preg, const char *string, size_t nmatch,
+int shm_regexec(shm_regex_t *preg, const char *string, size_t nmatch,
                    regmatch_t pmatch[], int eflags)
 {
 	malloc_hook_t	*orig_malloc_hook;
@@ -118,12 +125,24 @@ int shm_regexec(const regex_t *preg, const char *string, size_t nmatch,
 	 * It is safe to call regexec() concurrently without locking,
 	 * because regexec() has its own locks.
 	 * (Miklos)
+	 *
+	 * Those locks, however, don't work with shm and multi-core hardware
+	 * causing a dead-lock. Tested with glibc 2.3.6. (skeller)
 	 */
+
+	lock_get(&preg->lock);
 	replace_malloc_hooks();
-	ret = regexec(preg, string, nmatch,
+	ret = regexec(&preg->regexp, string, nmatch,
 			pmatch, eflags);
 	restore_malloc_hooks();
-	
+	lock_release(&preg->lock);
+
 	return ret;
 }
 
+size_t shm_regerror(int errcode, const shm_regex_t *preg, char *errbuf,
+                      size_t errbuf_size)
+{
+	return regerror(errcode, &preg->regexp, errbuf, errbuf_size);
+}
+
diff --git a/lib/shm_regex/shm_regex.h b/lib/shm_regex/shm_regex.h
index 42ec52b..aabf100 100644
--- a/lib/shm_regex/shm_regex.h
+++ b/lib/shm_regex/shm_regex.h
@@ -27,6 +27,8 @@
  * History
  * -------
  *  2009-04-03	Initial version (Miklos)
+ *  2010-04-25  Use own struct with locking to work-around libc locking failure
+ *              on multi-core hw (skeller)
  */
 
 #ifndef _SHM_REGEX_H
@@ -34,12 +36,18 @@
 
 #include <sys/types.h>
 #include <regex.h>
+#include "locking.h"
 
-int shm_regcomp(regex_t *preg, const char *regex, int cflags);
-void shm_regfree(regex_t *preg);
-int shm_regexec(const regex_t *preg, const char *string, size_t nmatch,
-                   regmatch_t pmatch[], int eflags);
+typedef struct shm_regex {
+	regex_t regexp;
+	gen_lock_t lock;
+} shm_regex_t;
 
-#define shm_regerror	regerror
+int shm_regcomp(shm_regex_t *preg, const char *regex, int cflags);
+void shm_regfree(shm_regex_t *preg);
+int shm_regexec(shm_regex_t *preg, const char *string, size_t nmatch,
+                   regmatch_t pmatch[], int eflags);
+size_t shm_regerror(int errcode, const shm_regex_t *preg, char *errbuf,
+                      size_t errbuf_size);
 
 #endif /* _SHM_REGEX_H */
-- 
1.7.0.4

Attachment: signature.asc
Description: PGP signature

_______________________________________________
sr-dev mailing list
[email protected]
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev

Reply via email to