GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/librthread/rthread_barrier.c Lines: 48 66 72.7 %
Date: 2017-11-07 Branches: 22 48 45.8 %

Line Branch Exec Source
1
/*	$OpenBSD: rthread_barrier.c,v 1.3 2016/04/15 17:54:17 tedu Exp $	*/
2
/*
3
 * Copyright (c) 2012 Paul Irofti <pirofti@openbsd.org>
4
 *
5
 * Permission to use, copy, modify, and/or distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
#include <errno.h>
19
#include <stdlib.h>
20
21
#include <pthread.h>
22
23
#include "rthread.h"
24
25
int
26
pthread_barrier_init(pthread_barrier_t *barrier, pthread_barrierattr_t *attr,
27
    unsigned int count) {
28
	int rc = 0;
29
	pthread_barrier_t b = NULL;
30
31
10
	if (barrier == NULL)
32
		return (EINVAL);
33
34
5
	if (attr != NULL) {
35
5
		if (*attr == NULL)
36
			return (EINVAL);
37
38
5
		if ((*attr)->pshared != PTHREAD_PROCESS_PRIVATE)
39
			return (ENOTSUP);
40
	}
41
42
5
	b = calloc(1, sizeof *b);
43
5
	if (b == NULL)
44
		return (ENOMEM);
45
46
5
	if ((rc = pthread_mutex_init(&b->mutex, NULL)))
47
		goto err;
48
5
	if ((rc = pthread_cond_init(&b->cond, NULL)))
49
		goto err;
50
51
5
	b->threshold = count;
52
53
5
	*barrier = b;
54
55
5
	return (0);
56
57
err:
58
	if (b) {
59
		if (b->mutex)
60
			pthread_mutex_destroy(&b->mutex);
61
		if (b->cond)
62
			pthread_cond_destroy(&b->cond);
63
		free(b);
64
	}
65
66
	return (rc);
67
5
}
68
69
int
70
pthread_barrier_destroy(pthread_barrier_t *barrier)
71
{
72
	int rc;
73
	pthread_barrier_t b;
74
75

15
	if (barrier == NULL || *barrier == NULL)
76
		return (EINVAL);
77
78
5
	if ((rc = pthread_mutex_lock(&(*barrier)->mutex)))
79
		return (rc);
80
81
5
	b = *barrier;
82
83

10
	if (b->out > 0 || b->in > 0) {
84
		pthread_mutex_unlock(&b->mutex);
85
		return (EBUSY);
86
	}
87
88
5
	*barrier = NULL;
89
5
	pthread_mutex_unlock(&b->mutex);
90
5
	pthread_mutex_destroy(&b->mutex);
91
5
	pthread_cond_destroy(&b->cond);
92
5
	free(b);
93
5
	return (0);
94
5
}
95
96
int
97
pthread_barrier_wait(pthread_barrier_t *barrier)
98
{
99
	pthread_barrier_t b;
100
100
	int rc, old_state, gen;
101
	int done = 0;
102
103

100
	if (barrier == NULL || *barrier == NULL)
104
		return (EINVAL);
105
106
50
	if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state)))
107
		return (rc);
108
109
50
	b = *barrier;
110
50
	if ((rc = pthread_mutex_lock(&b->mutex)))
111
		goto cancel;
112
113
50
	_rthread_debug(6, "in: %d, threshold: %d\n", b->in, b->threshold);
114
50
	if (++b->in == b->threshold) {
115
5
		b->out = b->in - 1;
116
5
		b->in = 0;
117
5
		b->generation++;
118
5
		if ((rc = pthread_cond_signal(&b->cond)))
119
			goto err;
120
		done = 1;
121
5
		_rthread_debug(6, "threshold reached\n");
122
5
	} else {
123
45
		gen = b->generation;
124
45
		_rthread_debug(6, "waiting on condition\n");
125
45
		do {
126
45
			if ((rc = pthread_cond_wait(&b->cond, &b->mutex)))
127
				goto err;
128
45
		} while (gen == b->generation);
129
45
		b->out--; /* mark thread exit */
130
45
		if ((rc = pthread_cond_signal(&b->cond)))
131
			goto err;
132
	}
133
134
err:
135
50
	if ((rc = pthread_mutex_unlock(&b->mutex)))
136
		return (rc);
137
cancel:
138
50
	rc = pthread_setcancelstate(old_state, NULL);
139
50
	if (rc == 0 && done)
140
		rc = PTHREAD_BARRIER_SERIAL_THREAD;
141
142
50
	return (rc);
143
50
}