[PATCH] libc: make I/O locking cancel-safe with futexes
Carmelo AMOROSO
carmelo.amoroso at st.com
Wed Sep 12 14:55:29 UTC 2012
From: Filippo ARCIDIACONO <filippo.arcidiacono at st.com>
Current implementation of I/O locking macros using futexes are not
cancel safe, as if a thread is cancelled while doing IO operations,
it does not release the lock on the IO stream. So following
attempts to acquire the IO stream's lock would dead-lock.
In order to make it cancel-safe, it needs to rely upon the
pthread_cleanup push & pop protocol, as it is already done for
the pthread_mutex counterpart.
Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono at st.com>
Signed-off-by: Carmelo Amoroso <carmelo.amoroso at st.com>
---
libc/stdio/Makefile.in | 3 ++
libc/stdio/io_lock_unlock.c | 16 ++++++++++++++
libc/sysdeps/linux/common/bits/uClibc_mutex.h | 23 +++++++++++++-------
libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h | 2 +
4 files changed, 36 insertions(+), 8 deletions(-)
create mode 100644 libc/stdio/io_lock_unlock.c
diff --git a/libc/stdio/Makefile.in b/libc/stdio/Makefile.in
index ff77bcb..4652036 100644
--- a/libc/stdio/Makefile.in
+++ b/libc/stdio/Makefile.in
@@ -52,6 +52,9 @@ endif
# pthread functions
CSRC += flockfile.c ftrylockfile.c funlockfile.c
+ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y)
+CSRC += io_lock_unlock.c
+endif
# Functions with unlocked versions
CUSRC := \
diff --git a/libc/stdio/io_lock_unlock.c b/libc/stdio/io_lock_unlock.c
new file mode 100644
index 0000000..b414264
--- /dev/null
+++ b/libc/stdio/io_lock_unlock.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2012 STMicroelectronics, Ltd
+ *
+ * Author(s): Filippo Arcidiacono <filippo.arcidiacono at st.com>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball
+ */
+
+#include <bits/stdio-lock.h>
+
+/* Function wrapper needed for I/O locking macros. */
+
+void IO_lock_unlock (_IO_lock_t *lock)
+{
+ _IO_lock_unlock (*lock);
+}
diff --git a/libc/sysdeps/linux/common/bits/uClibc_mutex.h b/libc/sysdeps/linux/common/bits/uClibc_mutex.h
index 94597e8..c2a1cc1 100644
--- a/libc/sysdeps/linux/common/bits/uClibc_mutex.h
+++ b/libc/sysdeps/linux/common/bits/uClibc_mutex.h
@@ -12,6 +12,7 @@
#ifdef __UCLIBC_HAS_THREADS__
+
#include <pthread.h>
#ifdef _LIBC
#include <bits/uClibc_pthread.h>
@@ -79,15 +80,21 @@
#define __UCLIBC_IO_MUTEX_INIT(M) _IO_lock_t M = _IO_lock_initializer
#define __UCLIBC_IO_MUTEX_EXTERN(M) extern _IO_lock_t M
-#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C) \
- if (C) { \
- _IO_lock_lock(M); \
- }
+#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C) \
+ do { \
+ struct _pthread_cleanup_buffer __infunc_pthread_cleanup_buffer; \
+ int __infunc_need_locking = (C); \
+ if (__infunc_need_locking) { \
+ _pthread_cleanup_push_defer(&__infunc_pthread_cleanup_buffer, \
+ (void (*) (void *))IO_lock_unlock, \
+ &(M)); \
+ _IO_lock_lock((M)); \
+ } \
+ ((void)0)
+
-#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C) \
- if (C) { \
- _IO_lock_unlock(M); \
- }
+#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C) \
+ __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M,C)
#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V) \
__UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,((A=(V))) == 0)
diff --git a/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h b/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h
index 3437e61..c742644 100644
--- a/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h
+++ b/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h
@@ -29,6 +29,8 @@
typedef struct { int lock; int cnt; void *owner; } _IO_lock_t;
+void IO_lock_unlock (_IO_lock_t *lock);
+
#define _IO_lock_initializer { LLL_LOCK_INITIALIZER, 0, NULL }
#define _IO_lock_init(_name) \
--
1.7.4.4
More information about the uClibc
mailing list