Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

VMDThreads.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2011 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: VMDThreads.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.87 $       $Date: 2011/02/17 17:25:17 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * VMDThreads.C - code for spawning threads on various platforms.
00020  *                Code donated by John Stone, john.stone@gmail.com 
00021  *                This code was originally written for the
00022  *                Tachyon Parallel/Multiprocessor Ray Tracer. 
00023  *                Improvements have been donated by Mr. Stone on an 
00024  *                ongoing basis. 
00025  *
00026  ***************************************************************************/
00027 
00028 #if 0
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <stdio.h>
00032 
00033 /* If compiling on Linux, enable the GNU CPU affinity functions in both */
00034 /* libc and the libpthreads                                             */
00035 /* #define VMDTHR_COMPAT_GLIBC232 1 */
00036 #if defined(__linux)
00037 #if defined(VMDTHR_COMPAT_GLIBC232)
00038 #include <gnu/libc-version.h>
00039 #endif
00040 #define _GNU_SOURCE 1
00041 #endif
00042 
00043 #include "VMDThreads.h"
00044 
00045 #ifdef _MSC_VER
00046 #include <windows.h>
00047 #include <winbase.h>
00048 #endif
00049 
00050 /* needed for call to sysconf() */
00051 #if defined(__sun) || defined(__linux) || defined(__irix) || defined(_CRAY) || defined(__osf__) || defined(_AIX)
00052 #include<unistd.h>
00053 #endif
00054 
00055 #if defined(__APPLE__) && defined(VMDTHREADS)
00056 #include <Carbon/Carbon.h> /* Carbon APIs for Multiprocessing */
00057 #endif
00058 
00059 #if defined(__hpux)
00060 #include <sys/mpctl.h>
00061 #endif
00062 
00063 
00064 #ifdef __cplusplus
00065 extern "C" {
00066 #endif
00067 
00068 
00069 int vmd_thread_numphysprocessors(void) {
00070   int a=1;
00071 
00072 #ifdef VMDTHREADS
00073 #if defined(__APPLE__) 
00074   a = MPProcessorsScheduled(); /* Number of active/running CPUs */
00075 #endif
00076 
00077 #ifdef _MSC_VER
00078   struct _SYSTEM_INFO sysinfo;
00079   GetSystemInfo(&sysinfo);
00080   a = sysinfo.dwNumberOfProcessors; /* total number of CPUs */
00081 #endif /* _MSC_VER */
00082 
00083 #if defined(_CRAY)
00084   a = sysconf(_SC_CRAY_NCPU);
00085 #endif
00086 
00087 #if defined(__sun) || defined(__linux) || defined(__osf__) || defined(_AIX)
00088   a = sysconf(_SC_NPROCESSORS_ONLN); /* number of active/running CPUs */
00089 #endif /* SunOS */
00090 
00091 #if defined(__irix)
00092   a = sysconf(_SC_NPROC_ONLN); /* number of active/running CPUs */
00093 #endif /* IRIX */
00094 
00095 #if defined(__hpux)
00096   a = mpctl(MPC_GETNUMSPUS, 0, 0); /* total number of CPUs */
00097 #endif /* HPUX */
00098 #endif /* VMDTHREADS */
00099 
00100   return a;
00101 }
00102 
00103 int vmd_thread_numprocessors(void) {
00104   int a=1;
00105 
00106 #ifdef VMDTHREADS
00107   /* Allow the user to override the number of CPUs for use */
00108   /* in scalability testing, debugging, etc.               */
00109   char *forcecount = getenv("VMDFORCECPUCOUNT");
00110   if (forcecount != NULL) {
00111     if (sscanf(forcecount, "%d", &a) == 1) {
00112       return a; /* if we got a valid count, return it */
00113     } else {
00114       a=1;      /* otherwise use the real available hardware CPU count */
00115     }
00116   }
00117 
00118   /* otherwise return the number of physical processors currently available */
00119   a = vmd_thread_numphysprocessors();
00120 
00121   /* XXX we should add checking for the current CPU affinity masks here, */
00122   /* and return the min of the physical processor count and CPU affinity */
00123   /* mask enabled CPU count.                                             */
00124 #endif /* VMDTHREADS */
00125 
00126   return a;
00127 }
00128 
00129 #if defined(__linux) && defined(VMDTHR_COMPAT_GLIBC232)
00130 int glib232compat_getaffinity(pid_t        pid,
00131                               unsigned int cpusetsize,
00132                               cpu_set_t*   mask,
00133                               int          (*p)(pid_t,cpu_set_t*)) {
00134   typedef int(*pt2Func)(pid_t,unsigned int,cpu_set_t*);
00135   if (strncmp(gnu_get_libc_version(),"2.3.2",6) == 0){
00136     return (*p)(pid,mask);
00137   }
00138   return ((pt2Func)(*p))(pid,cpusetsize,mask);
00139 }
00140 
00141 int glib232compat_setaffinity(pid_t        pid,
00142                               unsigned int cpusetsize,
00143                               cpu_set_t*   mask,
00144                               int          (*p)(pid_t,const cpu_set_t*)) {
00145   typedef int(*pt2Func)(pid_t,unsigned int,cpu_set_t*);
00146   if(strncmp(gnu_get_libc_version(),"2.3.2",6) == 0){
00147     return (*p)(pid,mask);
00148   }
00149   return ((pt2Func)(*p))(pid,cpusetsize,mask);
00150 }
00151 #endif /* __linux && VMDTHR_COMPAT_GLIBC232 */
00152 
00153                                 
00154 
00155 int * vmd_cpu_affinitylist(int *cpuaffinitycount) {
00156   int *affinitylist = NULL;
00157   *cpuaffinitycount = -1; /* return count -1 if unimplemented or err occurs */
00158 
00159 /* Win32 process affinity mask query */
00160 /* XXX untested, but based on the linux code, may work with a few tweaks */
00161 #if 0 && defined(_MSC_VER)
00162   HANDLE myproc = GetCurrentProcess(); /* returns a psuedo-handle */
00163   DWORD affinitymask, sysaffinitymask;
00164 
00165   if (!GetProcessAffinityMask(myproc, &affinitymask, &sysaffinitymask)) {
00166     /* count length of affinity list */
00167     int affinitycount=0;
00168     int i;
00169     for (i=0; i<31; i++) {
00170       affinitycount += (affinitymask >> i) & 0x1;
00171     }
00172   
00173     /* build affinity list */
00174     if (affinitycount > 0) {
00175       affinitylist = (int *) malloc(affinitycount * sizeof(int));
00176       if (affinitylist == NULL)
00177         return NULL;
00178 
00179       int curcount = 0;
00180       for (i=0; i<CPU_SETSIZE; i++) {
00181         if (CPU_ISSET(i, &affinitymask)) {
00182           affinitylist[curcount] = i;
00183           curcount++;
00184         }
00185       }
00186     }
00187 
00188     *cpuaffinitycount = affinitycount; /* return final affinity list */
00189   }
00190 #endif
00191 
00192 /* Linux process affinity mask query */
00193 #if defined(__linux)
00194 
00195 /* protect ourselves from some older Linux distros */
00196 #if defined(CPU_SETSIZE)
00197   int i;
00198   cpu_set_t affinitymask;
00199   int affinitycount=0;
00200 
00201 #if defined(VMDTHR_COMPAT_GLIBC232)
00202   typedef int(*pt2Func)(pid_t,cpu_set_t*);
00203   /* PID 0 refers to the current process */
00204   if (glib232compat_getaffinity(0, sizeof(affinitymask), &affinitymask,(pt2Func)&sched_getaffinity) < 0) {
00205 #else
00206   /* PID 0 refers to the current process */
00207   if (sched_getaffinity(0, sizeof(affinitymask), &affinitymask) < 0) {
00208 #endif
00209     perror("vmd_cpu_affinitylist: sched_getaffinity");
00210     return NULL;
00211   }
00212 
00213   /* count length of affinity list */
00214   for (i=0; i<CPU_SETSIZE; i++) {
00215     affinitycount += CPU_ISSET(i, &affinitymask);
00216   }
00217 
00218   /* build affinity list */
00219   if (affinitycount > 0) {
00220     affinitylist = (int *) malloc(affinitycount * sizeof(int));
00221     if (affinitylist == NULL)
00222       return NULL;
00223 
00224     int curcount = 0;
00225     for (i=0; i<CPU_SETSIZE; i++) {
00226       if (CPU_ISSET(i, &affinitymask)) {
00227         affinitylist[curcount] = i;
00228         curcount++;
00229       }
00230     }
00231   }
00232 
00233   *cpuaffinitycount = affinitycount; /* return final affinity list */
00234 #endif
00235 #endif
00236 
00237   /* MacOS X 10.5.x has a CPU affinity query/set capability finally      */
00238   /* http://developer.apple.com/releasenotes/Performance/RN-AffinityAPI/ */
00239 
00240   /* Solaris and HP-UX use pset_bind() and related functions, and they   */
00241   /* don't use the single-level mask-based scheduling mechanism that     */
00242   /* the others, use.  Instead, they use a hierarchical tree of          */
00243   /* processor sets and processes float within those, or are tied to one */
00244   /* processor that's a member of a particular set.                      */
00245 
00246   return affinitylist;
00247 }
00248 
00249 
00250 int vmd_thread_set_self_cpuaffinity(int cpu) {
00251   int status=-1; /* unsupported by default */
00252 
00253 #ifdef VMDTHREADS
00254 
00255 #if defined(__linux)
00256 #if 0
00257   /* XXX this code is too new even for RHEL4, though it runs on Fedora 7 */
00258   /* and other newer revs.                                               */
00259   /* NPTL systems can assign per-thread affinities this way              */
00260   cpu_set_t affinitymask;
00261   CPU_ZERO(&affinitymask); 
00262   CPU_SET(cpu, &affinitymask);
00263   status = pthread_setaffinity_np(pthread_self(), sizeof(affinitymask), &affinitymask);
00264 #else
00265   /* non-NPTL systems based on the clone() API must use this method      */
00266   cpu_set_t affinitymask;
00267   CPU_ZERO(&affinitymask); 
00268   CPU_SET(cpu, &affinitymask);
00269 
00270 #if defined(VMDTHR_COMPAT_GLIBC232)
00271   typedef int(*pt2Func)(pid_t,const cpu_set_t*);
00272   /* PID 0 refers to the current process */
00273   if ((status=glib232compat_setaffinity(0,sizeof(affinitymask),&affinitymask,(pt2Func)&sched_setaffinity)) < 0) {
00274 #else
00275   /* PID 0 refers to the current process */
00276   if ((status=sched_setaffinity(0, sizeof(affinitymask), &affinitymask)) < 0) {
00277 #endif
00278     perror("vmd_thread_set_self_cpuaffinitylist: sched_setaffinity");
00279     return status;
00280   }
00281 #endif
00282 
00283   /* call sched_yield() so new affinity mask takes effect immediately */
00284   sched_yield();
00285 #endif /* linux */
00286 
00287   /* MacOS X 10.5.x has a CPU affinity query/set capability finally      */
00288   /* http://developer.apple.com/releasenotes/Performance/RN-AffinityAPI/ */
00289 
00290   /* Solaris and HP-UX use pset_bind() and related functions, and they   */
00291   /* don't use the single-level mask-based scheduling mechanism that     */
00292   /* the others, use.  Instead, they use a hierarchical tree of          */
00293   /* processor sets and processes float within those, or are tied to one */
00294   /* processor that's a member of a particular set.                      */
00295 #endif
00296 
00297   return status;
00298 }
00299 
00300 
00301 int vmd_thread_setconcurrency(int nthr) {
00302   int status=0;
00303 
00304 #ifdef VMDTHREADS
00305 #if defined(__sun) 
00306 #ifdef USEPOSIXTHREADS 
00307   status = pthread_setconcurrency(nthr);
00308 #else
00309   status = thr_setconcurrency(nthr);
00310 #endif
00311 #endif /* SunOS */
00312 
00313 #if defined(__irix) || defined(_AIX)
00314   status = pthread_setconcurrency(nthr);
00315 #endif
00316 #endif /* VMDTHREADS */
00317 
00318   return status;
00319 }
00320 
00321 
00322 
00323 /* Typedef to eliminate compiler warning caused by C/C++ linkage conflict. */
00324 #ifdef __cplusplus
00325 extern "C" {
00326 #endif
00327   typedef void * (*VMDTHREAD_START_ROUTINE)(void *);
00328 #ifdef __cplusplus
00329 }
00330 #endif
00331 
00332 int vmd_thread_create(vmd_thread_t * thr, void * fctn(void *), void * arg) {
00333   int status=0;
00334 
00335 #ifdef VMDTHREADS 
00336 #ifdef _MSC_VER
00337   DWORD tid; /* thread id, msvc only */
00338   *thr = CreateThread(NULL, 8192, (LPTHREAD_START_ROUTINE) fctn, arg, 0, &tid);
00339   if (*thr == NULL) {
00340     status = -1;
00341   }
00342 #endif /* _MSC_VER */
00343 
00344 #ifdef USEPOSIXTHREADS 
00345 #if defined(_AIX)
00346   {
00347     pthread_attr_t attr;
00348     pthread_attr_init(&attr);
00349     pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
00350     status = pthread_create(thr, &attr, fctn, arg);
00351     pthread_attr_destroy(&attr);
00352   }
00353 #else   
00354   status = pthread_create(thr, NULL, (VMDTHREAD_START_ROUTINE)fctn, arg);
00355 #endif 
00356 #endif /* USEPOSIXTHREADS */
00357 #endif /* VMDTHREADS */
00358  
00359   return status;
00360 }
00361 
00362 
00363 int vmd_thread_join(vmd_thread_t thr, void ** stat) {
00364   int status=0;  
00365 
00366 #ifdef VMDTHREADS
00367 #ifdef _MSC_VER
00368   DWORD wstatus = 0;
00369  
00370   wstatus = WAIT_TIMEOUT;
00371  
00372   while (wstatus != WAIT_OBJECT_0) {
00373     wstatus = WaitForSingleObject(thr, INFINITE);
00374   }
00375 #endif /* _MSC_VER */
00376 
00377 #ifdef USEPOSIXTHREADS
00378   status = pthread_join(thr, stat);
00379 #endif /* USEPOSIXTHREADS */
00380 #endif /* VMDTHREADS */
00381 
00382   return status;
00383 }  
00384 
00385 
00386 int vmd_mutex_init(vmd_mutex_t * mp) {
00387   int status=0;
00388 
00389 #ifdef VMDTHREADS
00390 #ifdef _MSC_VER
00391   InitializeCriticalSection(mp);
00392 #endif /* _MSC_VER */
00393 
00394 #ifdef USEPOSIXTHREADS
00395   status = pthread_mutex_init(mp, 0);
00396 #endif /* USEPOSIXTHREADS */
00397 #endif /* VMDTHREADS */
00398 
00399   return status;
00400 }
00401 
00402 
00403 int vmd_mutex_lock(vmd_mutex_t * mp) {
00404   int status=0;
00405 
00406 #ifdef VMDTHREADS
00407 #ifdef _MSC_VER
00408   EnterCriticalSection(mp);
00409 #endif /* _MSC_VER */
00410 
00411 #ifdef USEPOSIXTHREADS
00412   status = pthread_mutex_lock(mp);
00413 #endif /* USEPOSIXTHREADS */
00414 #endif /* VMDTHREADS */
00415 
00416   return status;
00417 }
00418 
00419 
00420 int vmd_mutex_unlock(vmd_mutex_t * mp) {
00421   int status=0;
00422 
00423 #ifdef VMDTHREADS  
00424 #ifdef _MSC_VER
00425   LeaveCriticalSection(mp);
00426 #endif /* _MSC_VER */
00427 
00428 #ifdef USEPOSIXTHREADS
00429   status = pthread_mutex_unlock(mp);
00430 #endif /* USEPOSIXTHREADS */
00431 #endif /* VMDTHREADS */
00432 
00433   return status;
00434 }
00435 
00436 
00437 int vmd_mutex_destroy(vmd_mutex_t * mp) {
00438   int status=0;
00439 
00440 #ifdef VMDTHREADS
00441 #ifdef _MSC_VER
00442   DeleteCriticalSection(mp);
00443 #endif /* _MSC_VER */
00444 
00445 #ifdef USEPOSIXTHREADS
00446   status = pthread_mutex_destroy(mp);
00447 #endif /* USEPOSIXTHREADS */
00448 #endif /* VMDTHREADS */
00449 
00450   return status;
00451 }
00452 
00453 
00454 
00455 int vmd_cond_init(vmd_cond_t * cvp) {
00456   int status=0;
00457 
00458 #ifdef VMDTHREADS
00459 #ifdef _MSC_VER
00460 #if defined(VMDUSEWIN2008CONDVARS)
00461   InitializeConditionVariable(cvp);
00462 #else
00463   /* XXX not implemented */
00464   cvp->waiters = 0;
00465 
00466   /* Create an auto-reset event. */
00467   cvp->events[VMD_COND_SIGNAL] = CreateEvent(NULL,  /* no security */
00468                                              FALSE, /* auto-reset event */
00469                                              FALSE, /* non-signaled initially */
00470                                              NULL); /* unnamed */
00471 
00472   // Create a manual-reset event.
00473   cvp->events[VMD_COND_BROADCAST] = CreateEvent(NULL,  /* no security */
00474                                                 TRUE,  /* manual-reset */
00475                                                 FALSE, /* non-signaled initially*/
00476                                                 NULL); /* unnamed */
00477 #endif
00478 #endif /* _MSC_VER */
00479 
00480 #ifdef USEPOSIXTHREADS
00481   status = pthread_cond_init(cvp, NULL);
00482 #endif /* USEPOSIXTHREADS */
00483 #endif /* VMDTHREADS */
00484 
00485   return status;
00486 }
00487 
00488 int vmd_cond_destroy(vmd_cond_t * cvp) {
00489   int status=0;
00490 
00491 #ifdef VMDTHREADS
00492 #ifdef _MSC_VER
00493 #if defined(VMDUSEWIN2008CONDVARS)
00494   /* XXX not implemented */
00495 #else
00496   CloseHandle(cvp->events[VMD_COND_SIGNAL]);
00497   CloseHandle(cvp->events[VMD_COND_BROADCAST]);
00498 #endif
00499 #endif /* _MSC_VER */
00500 
00501 #ifdef USEPOSIXTHREADS
00502   status = pthread_cond_destroy(cvp);
00503 #endif /* USEPOSIXTHREADS */
00504 #endif /* VMDTHREADS */
00505 
00506   return status;
00507 }
00508 
00509 int vmd_cond_wait(vmd_cond_t * cvp, vmd_mutex_t * mp) {
00510   int status=0;
00511 
00512 #ifdef VMDTHREADS
00513 #ifdef _MSC_VER
00514 #if defined(VMDUSEWIN2008CONDVARS)
00515   SleepConditionVariableCS(cvp, mp, INFINITE)
00516 #else
00517 #if !defined(VMDUSEINTERLOCKEDATOMICOPS)
00518   EnterCriticalSection(&cvp->waiters_lock);
00519   cvp->waiters++;
00520   LeaveCriticalSection(&cvp->waiters_lock);
00521 #else
00522   InterlockedIncrement(&cvp->waiters);
00523 #endif
00524 
00525   LeaveCriticalSection(mp); /* SetEvent() maintains state, avoids lost wakeup */
00526 
00527   /* Wait either a single or broadcast even to become signalled */
00528   int result = WaitForMultipleObjects(2, cvp->events, FALSE, INFINITE);
00529 
00530 #if !defined(VMDUSEINTERLOCKEDATOMICOPS)
00531   EnterCriticalSection (&cvp->waiters_lock);
00532   cvp->waiters--;
00533   LONG last_waiter = 
00534     ((result == (WAIT_OBJECT_0 + VMD_COND_BROADCAST)) && cvp->waiters == 0);
00535   LeaveCriticalSection (&cvp->waiters_lock);
00536 #else
00537   LONG my_waiter = InterlockedDecrement(&cvp->waiters);
00538   LONG last_waiter = 
00539     ((result == (WAIT_OBJECT_0 + VMD_COND_BROADCAST)) && my_waiter == 0);
00540 #endif
00541 
00542   /* Some thread called cond_broadcast() */
00543   if (last_waiter)
00544     /* We're the last waiter to be notified or to stop waiting, so */
00545     /* reset the manual event.                                     */
00546     ResetEvent(cvp->events[VMD_COND_BROADCAST]); 
00547 
00548   EnterCriticalSection(mp);
00549 #endif
00550 #endif /* _MSC_VER */
00551 
00552 #ifdef USEPOSIXTHREADS
00553   status = pthread_cond_wait(cvp, mp);
00554 #endif /* USEPOSIXTHREADS */
00555 #endif /* VMDTHREADS */
00556 
00557   return status;
00558 }
00559 
00560 int vmd_cond_signal(vmd_cond_t * cvp) {
00561   int status=0;
00562 
00563 #ifdef VMDTHREADS
00564 #ifdef _MSC_VER
00565 #if defined(VMDUSEWIN2008CONDVARS)
00566   WakeConditionVariable(cvp);
00567 #else
00568 #if !defined(VMDUSEINTERLOCKEDATOMICOPS)
00569   EnterCriticalSection(&cvp->waiters_lock);
00570   int have_waiters = (cvp->waiters > 0);
00571   LeaveCriticalSection(&cvp->waiters_lock);
00572   if (have_waiters)
00573     SetEvent (cvp->events[VMD_COND_SIGNAL]);
00574 #else
00575   if (InterlockedExchangeAdd(&cvp->waiters, 0) > 0)
00576     SetEvent(cvp->events[VMD_COND_SIGNAL]);
00577 #endif
00578 #endif
00579 #endif /* _MSC_VER */
00580 
00581 #ifdef USEPOSIXTHREADS
00582   status = pthread_cond_signal(cvp);
00583 #endif /* USEPOSIXTHREADS */
00584 #endif /* VMDTHREADS */
00585 
00586   return status;
00587 }
00588 
00589 int vmd_cond_broadcast(vmd_cond_t * cvp) {
00590   int status=0;
00591 
00592 #ifdef VMDTHREADS
00593 #ifdef _MSC_VER
00594 #if defined(VMDUSEWIN2008CONDVARS)
00595   WakeAllConditionVariable(cvp);
00596 #else
00597 #if !defined(VMDUSEINTERLOCKEDATOMICOPS)
00598   EnterCriticalSection(&cvp->waiters_lock);
00599   int have_waiters = (cvp->waiters > 0);
00600   LeaveCriticalSection(&cvp->waiters_lock);
00601   if (have_waiters)
00602     SetEvent(cvp->events[VMD_COND_BROADCAST]);
00603 #else
00604   if (InterlockedExchangeAdd(&cvp->waiters, 0) > 0)
00605     SetEvent(cvp->events[VMD_COND_BROADCAST]);
00606 #endif
00607 
00608 #endif
00609 #endif /* _MSC_VER */
00610 
00611 #ifdef USEPOSIXTHREADS
00612   status = pthread_cond_broadcast(cvp);
00613 #endif /* USEPOSIXTHREADS */
00614 #endif /* VMDTHREADS */
00615 
00616   return status;
00617 }
00618   
00619 
00620 
00621 #if !defined(VMDTHREADS)
00622 
00623 int vmd_thread_barrier_init_proc_shared(vmd_barrier_t *barrier, int n_clients) {
00624   return 0;
00625 }
00626 
00627 void vmd_thread_barrier_destroy(vmd_barrier_t *barrier) {
00628 }
00629 
00630 int vmd_thread_barrier(vmd_barrier_t *barrier, int increment) {
00631   return 0;
00632 }
00633 
00634 #else 
00635 
00636 #ifdef USEPOSIXTHREADS
00637 
00638 /* When rendering in the CAVE we use a special synchronization    */
00639 /* mode so that shared memory mutexes and condition variables     */
00640 /* will work correctly when accessed from multiple processes.     */
00641 /* Inter-process synchronization involves the kernel to a greater */
00642 /* degree, so these barriers are substantially more costly to use */
00643 /* than the ones designed for use within a single-process.        */
00644 int vmd_thread_barrier_init_proc_shared(vmd_barrier_t *barrier, int n_clients) {
00645   if (barrier != NULL) {
00646     barrier->n_clients = n_clients;
00647     barrier->n_waiting = 0;
00648     barrier->phase = 0;
00649     barrier->sum = 0;
00650 
00651     pthread_mutexattr_t mattr;
00652     pthread_condattr_t  cattr;
00653 
00654     printf("Setting barriers to have system scope...\n");
00655 
00656     pthread_mutexattr_init(&mattr);
00657     if (pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED) != 0) {
00658       printf("WARNING: could not set mutex to process shared scope\n");
00659     }
00660 
00661     pthread_condattr_init(&cattr);
00662     if (pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED) != 0) {
00663       printf("WARNING: could not set mutex to process shared scope\n");
00664     }
00665 
00666     pthread_mutex_init(&barrier->lock, &mattr);
00667     pthread_cond_init(&barrier->wait_cv, &cattr);
00668 
00669     pthread_condattr_destroy(&cattr);
00670     pthread_mutexattr_destroy(&mattr);
00671   }
00672 
00673   return 0;
00674 }
00675 
00676 void vmd_thread_barrier_destroy(vmd_barrier_t *barrier) {
00677   pthread_mutex_destroy(&barrier->lock);
00678   pthread_cond_destroy(&barrier->wait_cv);
00679 }
00680 
00681 int vmd_thread_barrier(vmd_barrier_t *barrier, int increment) {
00682   int my_phase;
00683   int my_result;
00684 
00685   pthread_mutex_lock(&barrier->lock);
00686   my_phase = barrier->phase;
00687   barrier->sum += increment;
00688   barrier->n_waiting++;
00689 
00690   if (barrier->n_waiting == barrier->n_clients) {
00691     barrier->result = barrier->sum;
00692     barrier->sum = 0;
00693     barrier->n_waiting = 0;
00694     barrier->phase = 1 - my_phase;
00695     pthread_cond_broadcast(&barrier->wait_cv);
00696   }
00697 
00698   while (barrier->phase == my_phase) {
00699     pthread_cond_wait(&barrier->wait_cv, &barrier->lock);
00700   }
00701 
00702   my_result = barrier->result;
00703 
00704   pthread_mutex_unlock(&barrier->lock);
00705 
00706   return my_result;
00707 }
00708 
00709 #endif
00710 
00711 #endif /* VMDTHREADS */
00712 
00713 #ifdef __cplusplus
00714 }
00715 #endif
00716 
00717 #endif

Generated on Sun Feb 12 01:49:31 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002