b73a8ae1dda92f8287e975088be73d63b90d01db
[alexxy/gromacs.git] / src / gmxlib / thread_mpi / winthreads.c
1 /*
2 This source code file is part of thread_mpi.  
3 Written by Sander Pronk, Erik Lindahl, and possibly others. 
4
5 Copyright (c) 2009, Sander Pronk, Erik Lindahl.
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 1) Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12 2) Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15 3) Neither the name of the copyright holders nor the
16    names of its contributors may be used to endorse or promote products
17    derived from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
20 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 If you want to redistribute modifications, please consider that
31 scientific software is very special. Version control is crucial -
32 bugs must be traceable. We will be happy to consider code for
33 inclusion in the official distribution, but derived work should not
34 be called official thread_mpi. Details are found in the README & COPYING
35 files.
36
37 To help us fund development, we humbly ask that you cite
38 any papers on the package - you can find them in the top README file.
39
40 */
41
42
43
44 /* Include the defines that determine which thread library to use.
45 * We do not use HAVE_PTHREAD_H directly, since we might want to
46 * turn off thread support explicity (e.g. for debugging).
47 */
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #ifdef THREAD_WIN32
53
54 /* the win32 header */
55 #include <windows.h>
56
57
58 #include <errno.h>
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include <stdarg.h>
62
63
64 #include "thread_mpi/threads.h"
65
66 /*! \brief System mutex for all one-time initialization 
67  *
68  *  This static variable is necessary in order to make the header file 
69  *  independent of the thread library implementation. Anyway, it
70  *  will only be locked a handful of times at the start of program execution.
71  */
72 enum tMPI_Thread_once_status tMPI_Thread_system_lock_state=
73                              TMPI_THREAD_ONCE_STATUS_NOTCALLED;
74 static CRITICAL_SECTION tMPI_Thread_system_lock;
75
76
77
78 void tMPI_Fatal_error(const char *file, int line, const char *message, ...)
79 {
80     va_list ap;
81
82     fprintf(stderr, "tMPI Fatal error in %s, line %d: ", file, line);
83     va_start(ap, message);
84     vfprintf(stderr, message, ap);
85     va_end(ap);
86     fprintf(stderr,"\n");
87     abort();
88 }
89
90
91
92 enum tMPI_Thread_support tMPI_Thread_support(void)
93 {
94     return TMPI_THREAD_SUPPORT_YES;
95 }
96
97 struct tMPI_Thread_starter_param
98 {
99         void *(*start_routine)(void*); /* the function */
100         void *param; /* its parameter */
101 };
102
103 static DWORD WINAPI tMPI_Win32_thread_starter( LPVOID lpParam ) 
104 {
105         struct tMPI_Thread_starter_param *prm=
106                             (struct tMPI_Thread_starter_param*)lpParam;
107
108         (prm->start_routine)(prm->param);
109         return 0;
110 }
111
112
113 int tMPI_Thread_create(tMPI_Thread_t *thread,
114                        void *(*start_routine)(void *), void *arg)
115 {
116     DWORD thread_id;
117         struct tMPI_Thread_starter_param *prm;
118         
119         /* a small memory leak to be sure that it doesn't get deallocated 
120            once this function ends */
121         prm=malloc(sizeof(struct tMPI_Thread_starter_param));
122         prm->start_routine= start_routine;
123         prm->param=arg;
124
125     if(thread==NULL)
126     {
127         tMPI_Fatal_error(TMPI_FARGS,"Invalid thread pointer.");
128         return EINVAL;
129     }
130
131     *thread = CreateThread( NULL, 0, tMPI_Win32_thread_starter, prm, 0, &thread_id);
132
133     if(*thread==NULL)
134     {
135         tMPI_Fatal_error(TMPI_FARGS,"Failed to create thread, error code=%d",
136                          GetLastError());
137         return -1;
138     }
139
140     return 0;
141 }
142
143
144
145 int tMPI_Thread_join(tMPI_Thread_t thread, void **value_ptr)
146 {
147     DWORD ret,retval;
148
149     ret = WaitForSingleObject(thread, INFINITE);
150
151     if (ret != 0)
152     {
153         tMPI_Fatal_error(TMPI_FARGS,"Failed to join thread. error code=%d",
154                 GetLastError());
155         return -1;
156     }
157
158     if (value_ptr)
159     {
160         if (!GetExitCodeThread(thread, &retval))
161         {
162             /* TODO: somehow assign value_ptr */
163             tMPI_Fatal_error(TMPI_FARGS,"Failed to get thread exit code: error=%d",
164                     GetLastError());
165             return -1;
166         }
167     }
168     CloseHandle(thread);
169
170     return 0;
171 }
172
173
174 void tMPI_Thread_exit(void *value_ptr)
175 {
176     /* TODO: fix exit code */
177     /* TODO: call destructors for thread-local storage */
178     ExitThread( 0 );
179 }
180
181
182
183
184 int tMPI_Thread_cancel(tMPI_Thread_t thread)
185 {
186     if (!TerminateThread( thread, -1) )
187     {
188         tMPI_Fatal_error(TMPI_FARGS,"Failed thread_cancel, error code=%d",
189                          GetLastError());
190         return -1;
191     }
192     return 0;
193 }
194
195
196
197
198 int tMPI_Thread_mutex_init(tMPI_Thread_mutex_t *mtx) 
199 {
200     if(mtx==NULL)
201     {
202         return EINVAL;
203     }
204    
205     InitializeCriticalSection(&(mtx->cs));
206     mtx->init_state = TMPI_THREAD_ONCE_STATUS_READY;
207     
208     return 0;
209 }
210
211
212 int tMPI_Thread_mutex_destroy(tMPI_Thread_mutex_t *mtx) 
213 {
214     if(mtx == NULL)
215     {
216         return EINVAL;
217     }
218
219     DeleteCriticalSection(&(mtx->cs));
220
221     return 0;
222 }
223
224
225
226
227 static int tMPI_Thread_mutex_init_once(tMPI_Thread_mutex_t *mtx)
228 {
229     int ret;
230     
231     /* This is essentially a copy of the code from the one-time
232      * initialization, but with a call to the mutex init routine instead.
233      * It might seem like overkill, but it will only be executed the first
234      * time you call a static mutex, and it is important to get all the 
235      * memory barriers right. Trust me, you don't want a deadlock here...
236      */ 
237
238     /* Lock the common one-time init mutex so we can check carefully */
239     EnterCriticalSection( &tMPI_Thread_system_lock );
240
241
242 #if 0
243     /* If somebody is already initializing, wait until he is finished.
244     * In that case, the mutex will also be unlocked.
245     */
246     while (mtx->status == TMPI_THREAD_ONCE_STATUS_PROGRESS)
247         pthread_cond_wait (&tMPI_Thread_pthreads_system_cond,
248                            &tMPI_Thread_pthreads_system_mtx);
249 #endif
250     
251     /* Do the actual (locked) check - system mutex is locked if we get here */
252         if (mtx->init_state != TMPI_THREAD_ONCE_STATUS_READY)
253     {
254         /*mtx->status = TMPI_THREAD_ONCE_STATUS_PROGRESS;*/
255         
256         /* No need to keep the lock during execution -
257         * Only one thread can do it anyway.
258         */
259         /*pthread_mutex_unlock (&tMPI_Thread_pthreads_system_mtx);*/
260         ret=tMPI_Thread_mutex_init(mtx);
261         /*pthread_mutex_lock (&tMPI_Thread_pthreads_system_mtx);*/
262         
263         /* Status will be marked as ready by tMPI_Thread_mutex_init(). */ 
264         /*pthread_cond_broadcast (&tMPI_Thread_pthreads_system_cond);*/
265     }
266     else
267     {
268         ret = 0;
269     }
270     
271     LeaveCriticalSection( &tMPI_Thread_system_lock );
272
273     return ret;
274 }
275
276
277
278 int tMPI_Thread_mutex_lock(tMPI_Thread_mutex_t *mtx)
279 {
280     /* Ccheck whether this mutex is initialized */
281     if(mtx->init_state != TMPI_THREAD_ONCE_STATUS_READY)
282     {
283         tMPI_Thread_mutex_init_once(mtx);
284     }
285     
286     /* The mutex is now guaranteed to be valid. */
287     EnterCriticalSection( &(mtx->cs) );
288
289     return 0;
290 }
291
292  
293
294
295 int tMPI_Thread_mutex_trylock(tMPI_Thread_mutex_t *mtx)
296 {
297     BOOL ret;
298     
299     /* Ccheck whether this mutex is initialized */
300     if(mtx->init_state != TMPI_THREAD_ONCE_STATUS_READY)
301     {
302         tMPI_Thread_mutex_init_once(mtx);
303     }
304  
305     /* The mutex is now guaranteed to be valid. */
306     ret=TryEnterCriticalSection( &(mtx->cs) );
307       
308     return (ret != 0);
309 }
310
311
312
313 int tMPI_Thread_mutex_unlock(tMPI_Thread_mutex_t *mtx)
314 {
315         LeaveCriticalSection( &(mtx->cs) );
316     
317     return 0;
318 }
319
320
321
322 int tMPI_Thread_key_create(tMPI_Thread_key_t *key, void (*destructor)(void *))
323 {
324     if(key==NULL)
325     {
326         tMPI_Fatal_error(TMPI_FARGS,"Invalid key pointer.");
327         return EINVAL;
328     }
329
330
331     /* TODO: make list of destructors for thread-local storage */
332     *key=TlsAlloc();
333
334     if ( *key == TLS_OUT_OF_INDEXES ) 
335     {
336         tMPI_Fatal_error(TMPI_FARGS,"Failed to create thread key, error code=%d.",
337                          GetLastError());
338         return -1;
339     }
340
341     return 0;
342 }
343
344
345 int tMPI_Thread_key_delete(tMPI_Thread_key_t key)
346 {
347     TlsFree(key);
348        
349     return 0;
350 }
351
352
353
354 void * tMPI_Thread_getspecific(tMPI_Thread_key_t key)
355 {
356     void *p = NULL;
357
358     p=TlsGetValue(key);
359
360     return p;
361 }
362
363
364 int tMPI_Thread_setspecific(tMPI_Thread_key_t key, void *value)
365 {
366     BOOL ret;
367
368     ret = TlsSetValue(key, value);
369     
370     return ret==0;
371 }
372
373
374 static BOOL CALLBACK InitHandleWrapperFunction(PINIT_ONCE InitOnce,
375                                                PVOID Parameter,
376                                                PVOID *lpContext)
377 {
378     void (*fn)(void)=Parameter;
379
380     fn();
381
382     return TRUE;
383 }
384
385
386 int tMPI_Thread_once(tMPI_Thread_once_t *once_control, 
387                      void (*init_routine)(void))
388 {
389         BOOL bStatus;
390     bStatus = InitOnceExecuteOnce(once_control, InitHandleWrapperFunction, 
391                                   init_routine, NULL);
392
393     if (!bStatus)
394     {
395         tMPI_Fatal_error(TMPI_FARGS,"Failed to run thread_once routine");
396         return -1;
397     }
398    
399     return 0;
400 }
401     
402
403
404
405
406 int tMPI_Thread_cond_init(tMPI_Thread_cond_t *cond) 
407 {
408     if(cond==NULL)
409     {
410         return EINVAL;
411     }
412
413     InitializeConditionVariable( &(cond->cv) );
414     cond->init_state=TMPI_THREAD_ONCE_STATUS_READY;
415     return 0;
416 }
417
418
419 int tMPI_Thread_cond_destroy(tMPI_Thread_cond_t *cond) 
420 {
421     /* windows doesnt have this function */
422     return 0;
423 }
424
425
426
427
428 /*! \brief Static init routine for pthread barrier 
429  *
430  * \internal
431  *
432  * This is only used as a wrapper to enable static initialization
433  * of posix thread types together with out abstraction layer for tMPI_Thread.h
434  * 
435  * \param cond  Condition variable, must be statically initialized
436  *  
437  * \return status - 0 on success, or a standard error code.
438  */
439 static int tMPI_Thread_cond_init_once(tMPI_Thread_cond_t *cond)
440 {
441     int ret;
442     
443     /* This is essentially a copy of the code from the one-time
444     * initialization, but with a call to the cond init routine instead.
445     * It might seem like overkill, but it will only be executed the first
446     * time you call a static condition variable, and it is important to get 
447     * the memory barriers right. Trust me, you don't want a deadlock here...
448     */ 
449     /* Lock the common one-time init mutex so we can check carefully */
450     EnterCriticalSection( &tMPI_Thread_system_lock );
451     /* Do the actual (locked) check - system mutex is locked if we get here */
452         if (cond->init_state != TMPI_THREAD_ONCE_STATUS_READY)
453     {
454         ret=tMPI_Thread_cond_init(cond);
455     }
456     else
457     {
458         ret = 0;
459     }
460     LeaveCriticalSection( &tMPI_Thread_system_lock );
461     
462     return ret;
463 }
464
465
466
467 int tMPI_Thread_cond_wait(tMPI_Thread_cond_t *cond, tMPI_Thread_mutex_t *mtx)
468 {
469     BOOL ret;
470     
471     /* Ccheck whether this condition variable is initialized */
472     if(cond->init_state != TMPI_THREAD_ONCE_STATUS_READY)
473     {
474         tMPI_Thread_cond_init_once(cond);
475     }
476     if(mtx->init_state != TMPI_THREAD_ONCE_STATUS_READY)
477     {
478         tMPI_Thread_mutex_init_once(mtx);
479     }
480
481     ret=SleepConditionVariableCS (&(cond->cv), &(mtx->cs), INFINITE);
482
483     if (!ret)
484     {
485         tMPI_Fatal_error(TMPI_FARGS,"Failed wait for condition, error code=%d",
486                          GetLastError());
487         return -1;
488     }
489    
490     return 0;
491 }
492
493
494
495
496 int tMPI_Thread_cond_signal(tMPI_Thread_cond_t *cond)
497 {
498     /* Ccheck whether this condition variable is initialized */
499     if(cond->init_state != TMPI_THREAD_ONCE_STATUS_READY)
500     {
501         tMPI_Thread_cond_init_once(cond);
502     }
503     /* The condition variable is now guaranteed to be valid. */
504     WakeConditionVariable( &(cond->cv) );
505     
506     return 0;
507 }
508
509
510
511 int tMPI_Thread_cond_broadcast(tMPI_Thread_cond_t *cond)
512 {
513     /* Ccheck whether this condition variable is initialized */
514     if(cond->init_state != TMPI_THREAD_ONCE_STATUS_READY)
515     {
516         tMPI_Thread_cond_init_once(cond);
517     }
518     /* The condition variable is now guaranteed to be valid. */
519     WakeAllConditionVariable( &(cond->cv) );
520    
521     return 0;
522 }
523
524
525
526
527 int tMPI_Thread_barrier_init(tMPI_Thread_barrier_t *barrier, int n)
528 {
529         if(barrier==NULL)
530     {
531         return EINVAL;
532     }
533     
534     InitializeCriticalSection(&(barrier->cs));
535     InitializeConditionVariable(&(barrier->cv));
536        
537     barrier->threshold = n;
538     barrier->count     = n;
539     barrier->cycle     = 0;
540
541     barrier->init_state = TMPI_THREAD_ONCE_STATUS_READY;
542
543     return 0;
544 }
545
546
547
548 int tMPI_Thread_barrier_destroy(tMPI_Thread_barrier_t *barrier)
549 {   
550     if(barrier==NULL)
551     {
552         return EINVAL;
553     }
554
555
556     DeleteCriticalSection(&(barrier->cs));
557     
558     return 0;
559 }
560  
561
562
563 /*! \brief Static init routine for pthread barrier 
564  *
565  * \internal
566  *
567  * This is only used as a wrapper to enable static initialization
568  * of posix thread types together with out abstraction layer for tMPI_Thread.h
569  *
570  * \param barrier Statically initialized barrier type
571  * \param n       Number of members in barrier
572  * 
573  * \return status - 0 on success, or a standard error code.
574  */
575 static int tMPI_Thread_barrier_init_once(tMPI_Thread_barrier_t *barrier, int n)
576 {
577     int ret;
578     
579     /* This is essentially a copy of the code from the one-time
580     * initialization, but with a call to the cond init routine instead.
581     * It might seem like overkill, but it will only be executed the first
582     * time you call a static condition variable, and it is important to get 
583     * the memory barriers right. Trust me, you don't want a deadlock here...
584     */ 
585     /* Lock the common one-time init mutex so we can check carefully */
586     EnterCriticalSection( &tMPI_Thread_system_lock );
587     /* Do the actual (locked) check - system mutex is locked if we get here */
588     if (barrier->init_state != TMPI_THREAD_ONCE_STATUS_READY)
589     {
590         ret=tMPI_Thread_barrier_init(barrier, n);
591     }
592     else
593     {
594         ret = 0;
595     }
596     LeaveCriticalSection( &tMPI_Thread_system_lock );
597     
598     return ret;
599 }
600
601
602
603 int tMPI_Thread_barrier_wait(tMPI_Thread_barrier_t *barrier)
604 {
605     int    cycle;
606     BOOL    rc=FALSE;
607     int     ret=0;
608     /*tMPI_Thread_pthread_barrier_t *p;*/
609
610     if(barrier->init_state != TMPI_THREAD_ONCE_STATUS_READY)
611     {
612         tMPI_Thread_barrier_init_once(barrier,barrier->threshold);        
613     }
614
615     /*p = (tMPI_Thread_pthread_barrier_t*)barrier->actual_barrier;*/
616     
617     EnterCriticalSection( &(barrier->cs)  );
618
619     
620
621     cycle = barrier->cycle;
622     
623     /* Decrement the count atomically and check if it is zero.
624         * This will only be true for the last thread calling us.
625         */
626     if( --(barrier->count) <= 0 )
627     { 
628         barrier->cycle = !barrier->cycle;
629         barrier->count = barrier->threshold;
630
631         WakeAllConditionVariable( &(barrier->cv) );
632     }
633     else
634     {
635         while(cycle == barrier->cycle)
636         {
637             rc=SleepConditionVariableCS (&(barrier->cv), &(barrier->cs), 
638                                          INFINITE);
639             if(!rc) 
640             {
641                 ret=-1;
642                 break;
643             }
644         }
645     }
646     
647     LeaveCriticalSection( &(barrier->cs)  );
648     return ret;
649 }
650
651
652
653 void tMPI_lockfile(FILE *stream)
654 {
655 /*    flockfile(stream);*/
656         /* TODO: implement this */
657 }
658
659
660 void tMPI_unlockfile(FILE *stream)
661 {
662 /*    funlockfile(stream);*/
663         /* TODO: implement this */
664 }
665
666 #endif /* THREAD_WIN32  */