GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/thread/rthread_cond.c Lines: 0 69 0.0 %
Date: 2017-11-13 Branches: 0 54 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: rthread_cond.c,v 1.4 2017/09/05 02:40:54 guenther Exp $ */
2
/*
3
 * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org>
4
 * Copyright (c) 2012 Philip Guenther <guenther@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <assert.h>
20
#include <errno.h>
21
#include <pthread.h>
22
#include <stdint.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <unistd.h>
26
27
#include "rthread.h"
28
#include "cancel.h"
29
#include "synch.h"
30
31
int
32
pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attr)
33
{
34
	pthread_cond_t cond;
35
36
	cond = calloc(1, sizeof(*cond));
37
	if (cond == NULL)
38
		return (ENOMEM);
39
40
	if (attr == NULL)
41
		cond->clock = CLOCK_REALTIME;
42
	else
43
		cond->clock = (*attr)->ca_clock;
44
	*condp = cond;
45
46
	return (0);
47
}
48
DEF_STRONG(pthread_cond_init);
49
50
int
51
pthread_cond_destroy(pthread_cond_t *condp)
52
{
53
	pthread_cond_t cond;
54
55
	assert(condp != NULL);
56
	cond = *condp;
57
58
	if (cond != NULL) {
59
		if (cond->mutex != NULL) {
60
#define MSG "pthread_cond_destroy on condvar with waiters!\n"
61
			write(2, MSG, sizeof(MSG) - 1);
62
#undef MSG
63
			return (EBUSY);
64
		}
65
		free(cond);
66
	}
67
	*condp = NULL;
68
69
	return (0);
70
}
71
72
int
73
_rthread_cond_timedwait(pthread_cond_t cond, pthread_mutex_t *mutexp,
74
    const struct timespec *abs)
75
{
76
	struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp;
77
	struct tib *tib = TIB_GET();
78
	pthread_t self = tib->tib_thread;
79
	int error, rv = 0, canceled = 0, mutex_count = 0;
80
	clockid_t clock = cond->clock;
81
	int seq = cond->seq;
82
	PREP_CANCEL_POINT(tib);
83
84
	_rthread_debug(5, "%p: cond_timed %p,%p (%p)\n", self,
85
	    (void *)cond, (void *)mutex, (void *)mutex->owner);
86
87
	ENTER_DELAYED_CANCEL_POINT(tib, self);
88
89
#if notyet
90
	/* mark the condvar as being associated with this mutex */
91
	if (cond->mutex == NULL)
92
		atomic_cas_ptr(&cond->mutex, NULL, mutex);
93
94
	if (cond->mutex != mutex) {
95
		LEAVE_CANCEL_POINT_INNER(tib, 1);
96
		return (EINVAL);
97
	}
98
#endif
99
100
	/* snag the count in case this is a recursive mutex */
101
	if (mutex->type == PTHREAD_MUTEX_RECURSIVE)
102
		mutex_count = mutex->count;
103
104
	pthread_mutex_unlock(mutexp);
105
106
	do {
107
		/* If ``seq'' wraps you deserve to lose a signal. */
108
		error = _twait(&cond->seq, seq, clock, abs);
109
		/*
110
		* If we took a normal signal (not from cancellation) then
111
		* we should just go back to sleep without changing state
112
		* (timeouts, etc).
113
		*/
114
	} while ((error == EINTR) &&
115
	   (tib->tib_canceled == 0 || (tib->tib_cantcancel & CANCEL_DISABLED)));
116
117
	/* if timeout or canceled, make note of that */
118
	if (error == ETIMEDOUT)
119
		rv = ETIMEDOUT;
120
	else if (error == EINTR)
121
		canceled = 1;
122
123
	pthread_mutex_lock(mutexp);
124
125
	/* restore the mutex's count */
126
	if (mutex->type == PTHREAD_MUTEX_RECURSIVE)
127
		mutex->count = mutex_count;
128
129
	LEAVE_CANCEL_POINT_INNER(tib, canceled);
130
131
	return rv;
132
}
133
134
int
135
pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp,
136
    const struct timespec *abs)
137
{
138
	pthread_cond_t cond;
139
	int error;
140
141
	if (*condp == NULL) {
142
		if ((error = pthread_cond_init(condp, NULL)))
143
			return (error);
144
	}
145
146
	cond = *condp;
147
	if (abs == NULL || abs->tv_sec < 0 || abs->tv_nsec < 0 ||
148
	    abs->tv_nsec >= 1000000000)
149
		return (EINVAL);
150
151
	return (_rthread_cond_timedwait(cond, mutexp, abs));
152
}
153
154
int
155
pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp)
156
{
157
	pthread_cond_t cond;
158
	int error;
159
160
	if (*condp == NULL) {
161
		if ((error = pthread_cond_init(condp, NULL)))
162
			return (error);
163
	}
164
165
	cond = *condp;
166
	return (_rthread_cond_timedwait(cond, mutexp, NULL));
167
}
168
169
int
170
pthread_cond_signal(pthread_cond_t *condp)
171
{
172
	pthread_cond_t cond;
173
	int count;
174
175
	if (*condp == NULL)
176
		return (0);
177
178
	cond = *condp;
179
180
	atomic_inc_int(&cond->seq);
181
	count = _wake(&cond->seq, 1);
182
183
	_rthread_debug(5, "%p: cond_signal %p, %d awaken\n", pthread_self(),
184
	    (void *)cond, count);
185
186
	return (0);
187
}
188
189
int
190
pthread_cond_broadcast(pthread_cond_t *condp)
191
{
192
	pthread_cond_t cond;
193
	int count;
194
195
	if (*condp == NULL)
196
		return (0);
197
198
	cond = *condp;
199
200
	atomic_inc_int(&cond->seq);
201
#if notyet
202
	count = _requeue(&cond->seq, 1, INT_MAX, &cond->mutex->lock);
203
#else
204
	count = _wake(&cond->seq, INT_MAX);
205
#endif
206
207
	_rthread_debug(5, "%p: cond_broadcast %p, %d awaken\n", pthread_self(),
208
	    (void *)cond, count);
209
210
	return (0);
211
}