1//------------------------------------------------------------------------------
2// Copyright (c) 2016 by Lukasz Janyst <lukasz@jany.st>
3//------------------------------------------------------------------------------
4// This file is part of thread-bites.
5//
6// thread-bites is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// thread-bites is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with thread-bites. If not, see <http://www.gnu.org/licenses/>.
18//------------------------------------------------------------------------------
19
20#include "tb.h"
21#include "tb-private.h"
22
23#include <limits.h>
24#include <linux/futex.h>
25
26//------------------------------------------------------------------------------
27// Broadcast
28//------------------------------------------------------------------------------
29int tbthread_cond_broadcast(tbthread_cond_t *cond)
30{
31 tb_futex_lock(&cond->lock);
32 if(!cond->waiters)
33 goto exit;
34 ++cond->futex;
35 ++cond->broadcast_seq;
36 SYSCALL3(__NR_futex, &cond->futex, FUTEX_WAKE, INT_MAX);
37exit:
38 tb_futex_unlock(&cond->lock);
39 return 0;
40}
41
42//------------------------------------------------------------------------------
43// Signal
44//------------------------------------------------------------------------------
45int tbthread_cond_signal(tbthread_cond_t *cond)
46{
47 tb_futex_lock(&cond->lock);
48 if(cond->waiters == cond->signal_num)
49 goto exit;
50 ++cond->futex;
51 ++cond->signal_num;
52 SYSCALL3(__NR_futex, &cond->futex, FUTEX_WAKE, 1);
53exit:
54 tb_futex_unlock(&cond->lock);
55 return 0;
56}
57
58//------------------------------------------------------------------------------
59// Wait
60//------------------------------------------------------------------------------
61int tbthread_cond_wait(tbthread_cond_t *cond, tbthread_mutex_t *mutex)
62{
63 tb_futex_lock(&cond->lock);
64 int st = 0;
65
66 if(!cond->mutex)
67 cond->mutex = mutex;
68
69 if(cond->mutex != mutex) {
70 st = -EINVAL;
71 goto error;
72 }
73
74 st = tbthread_mutex_unlock(mutex);
75 if(st) goto error;
76
77 ++cond->waiters;
78 int bseq = cond->broadcast_seq;
79 int futex = cond->futex;
80 tb_futex_unlock(&cond->lock);
81
82 while(1) {
83 st = SYSCALL3(__NR_futex, &cond->futex, FUTEX_WAIT, futex);
84 if(st == -EINTR)
85 continue;
86
87 tb_futex_lock(&cond->lock);
88 if(cond->signal_num) {
89 --cond->signal_num;
90 goto exit;
91 }
92
93 if(bseq != cond->broadcast_seq)
94 goto exit;
95 tb_futex_unlock(&cond->lock);
96 }
97
98error:
99 if(!cond->waiters)
100 cond->mutex = 0;
101
102 tb_futex_unlock(&cond->lock);
103 return st;
104
105exit:
106 --cond->waiters;
107 if(!cond->waiters)
108 cond->mutex = 0;
109
110 tb_futex_unlock(&cond->lock);
111 tbthread_mutex_lock(mutex);
112 return st;
113}
114