1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <endian.h>
21: #include <errno.h>
22: #include <sysdep.h>
23: #include <lowlevellock.h>
24: #include <pthread.h>
25: #include <pthreadP.h>
26: #include <kernel-features.h>
27:
28: #include <shlib-compat.h>
29:
30:
31:
32: extern void __condvar_cleanup (void *arg)
33: __attribute__ ((visibility ("hidden")));
34:
35: struct _condvar_cleanup_buffer
36: {
37: int oldtype;
38: pthread_cond_t *cond;
39: pthread_mutex_t *mutex;
40: unsigned int bc_seq;
41: };
42:
43: int
44: __pthread_cond_timedwait (cond, mutex, abstime)
45: pthread_cond_t *cond;
46: pthread_mutex_t *mutex;
47: const struct timespec *abstime;
48: {
49: struct _pthread_cleanup_buffer buffer;
50: struct _condvar_cleanup_buffer cbuffer;
51: int result = 0;
52:
53:
54: if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
55: return EINVAL;
56:
57: int pshared = (cond->__data.__mutex == (void *) ~0l)
58: ? LLL_SHARED : LLL_PRIVATE;
59:
60:
61: lll_lock (cond->__data.__lock, pshared);
62:
63:
64: int err = __pthread_mutex_unlock_usercnt (mutex, 0);
65: if (err)
66: {
67: lll_unlock (cond->__data.__lock, pshared);
68: return err;
69: }
70:
71:
72: ++cond->__data.__total_seq;
73: ++cond->__data.__futex;
74: cond->__data.__nwaiters += 1 << COND_NWAITERS_SHIFT;
75:
76:
77:
78:
79: if (cond->__data.__mutex != (void *) ~0l)
80: cond->__data.__mutex = mutex;
81:
82:
83: cbuffer.cond = cond;
84: cbuffer.mutex = mutex;
85:
86:
87:
88: __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer);
89:
90:
91:
92: unsigned long long int val;
93: unsigned long long int seq;
94: val = seq = cond->__data.__wakeup_seq;
95:
96: cbuffer.bc_seq = cond->__data.__broadcast_seq;
97:
98: while (1)
99: {
100: struct timespec rt;
101: {
102: #ifdef __NR_clock_gettime
103: INTERNAL_SYSCALL_DECL (err);
104: int ret;
105: ret = INTERNAL_SYSCALL (clock_gettime, err, 2,
106: (cond->__data.__nwaiters
107: & ((1 << COND_NWAITERS_SHIFT) - 1)),
108: &rt);
109: # ifndef __ASSUME_POSIX_TIMERS
110: if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (ret, err), 0))
111: {
112: struct timeval tv;
113: (void) gettimeofday (&tv, NULL);
114:
115:
116: rt.tv_sec = abstime->tv_sec - tv.tv_sec;
117: rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
118: }
119: else
120: # endif
121: {
122:
123: rt.tv_sec = abstime->tv_sec - rt.tv_sec;
124: rt.tv_nsec = abstime->tv_nsec - rt.tv_nsec;
125: }
126: #else
127:
128: struct timeval tv;
129: (void) gettimeofday (&tv, NULL);
130:
131:
132: rt.tv_sec = abstime->tv_sec - tv.tv_sec;
133: rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
134: #endif
135: }
136: if (rt.tv_nsec < 0)
137: {
138: rt.tv_nsec += 1000000000;
139: --rt.tv_sec;
140: }
141:
142: if (__builtin_expect (rt.tv_sec < 0, 0))
143: {
144: if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
145: goto bc_out;
146:
147: goto timeout;
148: }
149:
150: unsigned int futex_val = cond->__data.__futex;
151:
152:
153: lll_unlock (cond->__data.__lock, pshared);
154:
155:
156: cbuffer.oldtype = __pthread_enable_asynccancel ();
157:
158:
159: err = lll_futex_timed_wait (&cond->__data.__futex,
160: futex_val, &rt, pshared);
161:
162:
163: __pthread_disable_asynccancel (cbuffer.oldtype);
164:
165:
166: lll_lock (cond->__data.__lock, pshared);
167:
168:
169: if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
170: goto bc_out;
171:
172:
173: val = cond->__data.__wakeup_seq;
174: if (val != seq && cond->__data.__woken_seq != val)
175: break;
176:
177:
178: if (__builtin_expect (err == -ETIMEDOUT, 0))
179: {
180: timeout:
181:
182: ++cond->__data.__wakeup_seq;
183: ++cond->__data.__futex;
184:
185:
186: result = ETIMEDOUT;
187: break;
188: }
189: }
190:
191:
192: ++cond->__data.__woken_seq;
193:
194: bc_out:
195:
196: cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT;
197:
198:
199:
200:
201: if (cond->__data.__total_seq == -1ULL
202: && cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT))
203: lll_futex_wake (&cond->__data.__nwaiters, 1, pshared);
204:
205:
206: lll_unlock (cond->__data.__lock, pshared);
207:
208:
209: __pthread_cleanup_pop (&buffer, 0);
210:
211:
212: err = __pthread_mutex_cond_lock (mutex);
213:
214: return err ?: result;
215: }
216:
217: versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
218: GLIBC_2_3_2);