GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/librthread/rthread_barrier.c Lines: 48 66 72.7 %
Date: 2017-11-13 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
6
	if (barrier == NULL)
32
		return (EINVAL);
33
34
3
	if (attr != NULL) {
35
3
		if (*attr == NULL)
36
			return (EINVAL);
37
38
3
		if ((*attr)->pshared != PTHREAD_PROCESS_PRIVATE)
39
			return (ENOTSUP);
40
	}
41
42
3
	b = calloc(1, sizeof *b);
43
3
	if (b == NULL)
44
		return (ENOMEM);
45
46
3
	if ((rc = pthread_mutex_init(&b->mutex, NULL)))
47
		goto err;
48
3
	if ((rc = pthread_cond_init(&b->cond, NULL)))
49
		goto err;
50
51
3
	b->threshold = count;
52
53
3
	*barrier = b;
54
55
3
	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
3
}
68
69
int
70
pthread_barrier_destroy(pthread_barrier_t *barrier)
71
{
72
	int rc;
73
	pthread_barrier_t b;
74
75

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

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

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