• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2    Copyright (c) 2011-2016  mingw-w64 project
3 
4    Permission is hereby granted, free of charge, to any person obtaining a
5    copy of this software and associated documentation files (the "Software"),
6    to deal in the Software without restriction, including without limitation
7    the rights to use, copy, modify, merge, publish, distribute, sublicense,
8    and/or sell copies of the Software, and to permit persons to whom the
9    Software is furnished to do so, subject to the following conditions:
10 
11    The above copyright notice and this permission notice shall be included in
12    all copies or substantial portions of the Software.
13 
14    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20    DEALINGS IN THE SOFTWARE.
21 */
22 
23 #include <windows.h>
24 #include <stdio.h>
25 #include <malloc.h>
26 #include "pthread.h"
27 #include "barrier.h"
28 #include "ref.h"
29 #include "misc.h"
30 
31 static pthread_spinlock_t barrier_global = PTHREAD_SPINLOCK_INITIALIZER;
32 
33 static WINPTHREADS_ATTRIBUTE((noinline)) int
barrier_unref(volatile pthread_barrier_t * barrier,int res)34 barrier_unref(volatile pthread_barrier_t *barrier, int res)
35 {
36     pthread_spin_lock(&barrier_global);
37 #ifdef WINPTHREAD_DBG
38     assert((((barrier_t *)*barrier)->valid == LIFE_BARRIER) && (((barrier_t *)*barrier)->busy > 0));
39 #endif
40      ((barrier_t *)*barrier)->busy -= 1;
41     pthread_spin_unlock(&barrier_global);
42     return res;
43 }
44 
barrier_ref(volatile pthread_barrier_t * barrier)45 static WINPTHREADS_ATTRIBUTE((noinline)) int barrier_ref(volatile pthread_barrier_t *barrier)
46 {
47     int r = 0;
48     pthread_spin_lock(&barrier_global);
49 
50     if (!barrier || !*barrier || ((barrier_t *)*barrier)->valid != LIFE_BARRIER) r = EINVAL;
51     else {
52         ((barrier_t *)*barrier)->busy += 1;
53     }
54 
55     pthread_spin_unlock(&barrier_global);
56 
57     return r;
58 }
59 
60 static WINPTHREADS_ATTRIBUTE((noinline))  int
barrier_ref_destroy(volatile pthread_barrier_t * barrier,pthread_barrier_t * bDestroy)61 barrier_ref_destroy(volatile pthread_barrier_t *barrier, pthread_barrier_t *bDestroy)
62 {
63     int r = 0;
64 
65     *bDestroy = NULL;
66     pthread_spin_lock(&barrier_global);
67 
68     if (!barrier || !*barrier || ((barrier_t *)*barrier)->valid != LIFE_BARRIER) r = EINVAL;
69     else {
70         barrier_t *b_ = (barrier_t *)*barrier;
71         if (b_->busy) r = EBUSY;
72         else {
73             *bDestroy = *barrier;
74             *barrier = NULL;
75         }
76     }
77 
78     pthread_spin_unlock(&barrier_global);
79     return r;
80 }
81 
82 static WINPTHREADS_ATTRIBUTE((noinline)) void
barrier_ref_set(volatile pthread_barrier_t * barrier,void * v)83 barrier_ref_set (volatile pthread_barrier_t *barrier, void *v)
84 {
85   pthread_spin_lock(&barrier_global);
86   *barrier = v;
87   pthread_spin_unlock(&barrier_global);
88 }
89 
pthread_barrier_destroy(pthread_barrier_t * b_)90 int pthread_barrier_destroy(pthread_barrier_t *b_)
91 {
92     pthread_barrier_t bDestroy;
93     barrier_t *b;
94     int r;
95 
96     while ((r = barrier_ref_destroy(b_,&bDestroy)) == EBUSY)
97       Sleep(0);
98 
99     if (r)
100       return r;
101 
102     b = (barrier_t *)bDestroy;
103 
104     pthread_mutex_lock(&b->m);
105 
106     if (sem_destroy(&b->sems[0]) != 0)
107     {
108         /* Could this happen? */
109         *b_ = bDestroy;
110         pthread_mutex_unlock (&b->m);
111         return EBUSY;
112     }
113     if (sem_destroy(&b->sems[1]) != 0)
114     {
115       sem_init (&b->sems[0], b->share, 0);
116       *b_ = bDestroy;
117       pthread_mutex_unlock (&b->m);
118       return -1;
119     }
120     pthread_mutex_unlock(&b->m);
121     if(pthread_mutex_destroy(&b->m) != 0) {
122      sem_init (&b->sems[0], b->share, 0);
123      sem_init (&b->sems[1], b->share, 0);
124      *b_ = bDestroy;
125      return -1;
126     }
127     b->valid = DEAD_BARRIER;
128     free(bDestroy);
129     return 0;
130 
131 }
132 
133 int
pthread_barrier_init(pthread_barrier_t * b_,const void * attr,unsigned int count)134 pthread_barrier_init (pthread_barrier_t *b_, const void *attr,
135 		      unsigned int count)
136 {
137     barrier_t *b;
138 
139     if (!count || !b_)
140       return EINVAL;
141 
142     if (!(b = (pthread_barrier_t)calloc(1,sizeof(*b))))
143        return ENOMEM;
144     if (!attr || *((int **)attr) == NULL)
145       b->share = PTHREAD_PROCESS_PRIVATE;
146     else
147       memcpy (&b->share, *((void **) attr), sizeof (int));
148     b->total = count;
149     b->count = count;
150     b->valid = LIFE_BARRIER;
151     b->sel = 0;
152 
153     if (pthread_mutex_init(&b->m, NULL) != 0)
154     {
155       free (b);
156       return ENOMEM;
157     }
158 
159     if (sem_init(&b->sems[0], b->share, 0) != 0)
160     {
161        pthread_mutex_destroy(&b->m);
162        free (b);
163        return ENOMEM;
164     }
165     if (sem_init(&b->sems[1], b->share, 0) != 0)
166     {
167        pthread_mutex_destroy(&b->m);
168        sem_destroy(&b->sems[0]);
169        free (b);
170        return ENOMEM;
171     }
172     barrier_ref_set (b_,b);
173 
174     return 0;
175 }
176 
pthread_barrier_wait(pthread_barrier_t * b_)177 int pthread_barrier_wait(pthread_barrier_t *b_)
178 {
179   long sel;
180   int r, e, rslt;
181   barrier_t *b;
182 
183   r = barrier_ref(b_);
184   if(r) return r;
185 
186   b = (barrier_t *)*b_;
187 
188   if ((r = pthread_mutex_lock(&b->m))) return  barrier_unref(b_,EINVAL);
189   sel = b->sel;
190   InterlockedDecrement((long*)&b->total);
191   if (b->total == 0)
192   {
193     b->total = b->count;
194     b->sel = (sel != 0 ? 0 : 1);
195     e = 1;
196     rslt = PTHREAD_BARRIER_SERIAL_THREAD;
197     r = (b->count > 1 ? sem_post_multiple (&b->sems[sel], b->count - 1) : 0);
198   }
199   else { e = 0; rslt= 0; }
200   pthread_mutex_unlock(&b->m);
201   if (!e)
202     r = sem_wait(&b->sems[sel]);
203 
204   if (!r) r = rslt;
205   return barrier_unref(b_,r);
206 }
207 
pthread_barrierattr_init(void ** attr)208 int pthread_barrierattr_init(void **attr)
209 {
210   int *p;
211 
212   if (!(p = (int *) calloc (1, sizeof (int))))
213     return ENOMEM;
214 
215   *p = PTHREAD_PROCESS_PRIVATE;
216   *attr = p;
217 
218   return 0;
219 }
220 
pthread_barrierattr_destroy(void ** attr)221 int pthread_barrierattr_destroy(void **attr)
222 {
223   void *p;
224   if (!attr || (p = *attr) == NULL)
225     return EINVAL;
226   *attr = NULL;
227   free (p);
228   return 0;
229 }
230 
pthread_barrierattr_setpshared(void ** attr,int s)231 int pthread_barrierattr_setpshared(void **attr, int s)
232 {
233   if (!attr || *attr == NULL
234       || (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE))
235     return EINVAL;
236   memcpy (*attr, &s, sizeof (int));
237   return 0;
238 }
239 
pthread_barrierattr_getpshared(void ** attr,int * s)240 int pthread_barrierattr_getpshared(void **attr, int *s)
241 {
242   if (!attr || !s || *attr == NULL)
243     return EINVAL;
244   memcpy (s, *attr, sizeof (int));
245   return 0;
246 }
247