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 |
} |