aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichał Łyszczek <michal.lyszczek@bofc.pl>2018-09-19 14:25:56 +0200
committerMichał Łyszczek <michal.lyszczek@bofc.pl>2018-09-19 14:25:56 +0200
commit83e8233dd0b8a5ad4ea7071ea58e85f736454f12 (patch)
treeb5135347bc6f7988c9f3c7e7312081654584ac6a
parentdd816b65c24fd9159f37947fba73209a801b92e1 (diff)
downloadlibrb-83e8233dd0b8a5ad4ea7071ea58e85f736454f12.tar.gz
librb-83e8233dd0b8a5ad4ea7071ea58e85f736454f12.tar.bz2
librb-83e8233dd0b8a5ad4ea7071ea58e85f736454f12.zip
fix: deadlock by assuming select() is thread safe
It is not.
-rw-r--r--man/rb_overview.76
-rw-r--r--man/rb_write.310
-rw-r--r--rb.c37
3 files changed, 8 insertions, 45 deletions
diff --git a/man/rb_overview.7 b/man/rb_overview.7
index 06c5c46..4625f8c 100644
--- a/man/rb_overview.7
+++ b/man/rb_overview.7
@@ -122,8 +122,7 @@ Upon entering any of the
.B POSIX
function, entering thread will lock read or write mutex, meaning when thread 1
enters any read function, no other thread will be able to read until thread 1
-completly finishes its read (there is on exception to this rule explained
-later).
+completly finishes its read.
Now you can see the problem, thread 1 may go in and perform
.BR read ()
on super slow socket and it will block threads that may also want to read into
@@ -133,9 +132,6 @@ object but from different, much faster socket.
This situation, of course, can occur only when multiple threads uses same
.B rb
object.
-As stated before, there is one exception to this rule.
-Until thread 1 (the one using slow socket) reads anything from the socket it
-doesn't block any other threads.
.SH EXAMPLE
.PP
Please note, that example is missing error handling for simplicity.
diff --git a/man/rb_write.3 b/man/rb_write.3
index caae337..0912a04 100644
--- a/man/rb_write.3
+++ b/man/rb_write.3
@@ -188,9 +188,13 @@ As usual, error handling ommited for clarity.
for (;;)
{
/* rb_posix_write() will sleep current thread until
- * data shows up on data->fd file descriptor. Until
- * this thread writes any data to rb, it won't block
- * other threads that wants to use rb_write() functions.
+ * data shows up on data->fd file descriptor.
+ *
+ * NOTE: you should be carefull here, as calling this
+ * function on slow data->fd will block other threads.
+ * rb will try to call read() on data->fd and read()
+ * will block until any data shows on data->fd, and
+ * if data->fd is slow, this may take a long time.
*/
if (rb_posix_write(data->rb, data->fd,
diff --git a/rb.c b/rb.c
index 07ecd9f..88543ce 100644
--- a/rb.c
+++ b/rb.c
@@ -908,12 +908,6 @@ static long rb_recvt
pthread_mutex_unlock(&rb->lock);
trace(("i/rb unlock"));
- if (r == 0)
- {
- pthread_mutex_unlock(&rb->rlock);
- trace(("i/rlock unlock"));
- }
-
tv.tv_sec = 0;
tv.tv_usec = 0;
@@ -929,12 +923,6 @@ static long rb_recvt
sact = select(fd + 1, NULL, &fds, NULL, NULL);
}
- if (r == 0)
- {
- trace(("i/rlock lock"));
- pthread_mutex_lock(&rb->rlock);
- }
-
trace(("i/rb lock"));
pthread_mutex_lock(&rb->lock);
rb_del_blocked_thread(rb);
@@ -1412,21 +1400,6 @@ long rb_sendt
pthread_mutex_unlock(&rb->lock);
trace(("i/rb unlock"));
- if (w == 0)
- {
- /*
- * we didn't write anything to rb just yet, so we can unlock
- * another wlock, so other thread can write to rb, while we
- * wait. If we don't unlock it we risk situation where t1
- * calls this function, then blocks for days on select()
- * waiting for some data to arrive, blocking every thread
- * that may receive data much faster.
- */
-
- trace(("i/wlock unlock"));
- pthread_mutex_unlock(&rb->wlock);
- }
-
tv.tv_sec = 0;
tv.tv_usec = 0;
@@ -1450,16 +1423,6 @@ long rb_sendt
sact = select(fd + 1, &fds, NULL, NULL, NULL);
}
- if (w == 0)
- {
- /*
- * ok, blocking is done, relock wlock again
- */
-
- trace(("i/wlock lock"));
- pthread_mutex_lock(&rb->wlock);
- }
-
trace(("i/rb lock"));
pthread_mutex_lock(&rb->lock);
rb_del_blocked_thread(rb);