001: /* ///////////////////////////// P /// L /// A /// S /// M /// A /////////////////////////////// */
002: /* ///                    PLASMA auxiliary routines (version 2.1.0)                          ///
003:  * ///                    Author: Piotr Luszczek                                             ///
004:  * ///                    Release Date: November, 15th 2009                                  ///
005:  * ///                    PLASMA is a software package provided by Univ. of Tennessee,       ///
006:  * ///                    Univ. of California Berkeley and Univ. of Colorado Denver          /// */
007: /* ///////////////////////////////////////////////////////////////////////////////////////////// */
008: 
009: /* This file handles the mapping from pthreads calls to windows threads */
010: 
011: #include "plasmawinthread.h"
012: 
013: #include <limits.h>
014: 
015: /* this is needed to get a declaration for _beginthreadex() */
016: #include <process.h>
017: 
018: #include <stdio.h>
019: #include <plasma.h>
020: 
021: PLASMA_DLLPORT unsigned int PLASMA_CDECL pthread_self_id(void) {
022:   return GetCurrentThreadId();
023: }
024: 
025: PLASMA_DLLPORT pthread_t PLASMA_CDECL pthread_self(void) {
026:   pthread_t pt;
027: 
028:   pt.hThread = GetCurrentThread();
029:   pt.uThId = GetCurrentThreadId();
030:   return pt;
031: }
032: 
033: PLASMA_DLLPORT int PLASMA_CDECL pthread_equal(pthread_t thread1, pthread_t thread2) {
034:   if (thread1.uThId == thread2.uThId) // && thread1.hThread == thread2.hThread)
035:     return 1;
036:   return 0;
037: }
038: 
039: PLASMA_DLLPORT int PLASMA_CDECL pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t * attr) {
040:   *mutex =
041:   CreateMutex( NULL,  /* no security atributes */
042:                FALSE, /* not owned (initialy) by the creating thread */
043:                NULL   /* no name provided: cannot be shared between processes */
044:   );
045: 
046:   return 0;
047: }
048: 
049: PLASMA_DLLPORT int PLASMA_CDECL pthread_mutex_lock(pthread_mutex_t *mutex) {
050:   DWORD rv;
051: 
052:   rv = WaitForSingleObject( *mutex, INFINITE );
053:   switch (rv) {
054:     case WAIT_OBJECT_0: /* the wait was succesful */
055:       return 0;
056:     case WAIT_FAILED: /* the wait failed */
057:       return -1;
058:     case WAIT_ABANDONED: /* thread killed during the wait */
059:       return -1;
060:     case WAIT_TIMEOUT: /* impossible because of INFINITE */
061:       return -1;
062:     default:
063:       return -1;
064:   }
065: }
066: 
067: PLASMA_DLLPORT int PLASMA_CDECL pthread_mutex_unlock(pthread_mutex_t *mutex) {
068:   if (! ReleaseMutex( *mutex ))
069:     return -1;
070: 
071:   return 0;
072: }
073: 
074: PLASMA_DLLPORT int PLASMA_CDECL pthread_mutex_destroy(pthread_mutex_t *mutex) {
075:   CloseHandle( *mutex );
076:   return 0;
077: }
078: 
079: PLASMA_DLLPORT int PLASMA_CDECL pthread_attr_init(pthread_attr_t *attr) {
080:   *attr = 1;
081:   return 0;
082: }
083: 
084: PLASMA_DLLPORT int PLASMA_CDECL pthread_attr_destroy(pthread_attr_t *attr) {
085:   *attr = 0;
086:   return 0;
087: }
088: 
089: PLASMA_DLLPORT int PLASMA_CDECL pthread_attr_setscope(pthread_attr_t *attr, int scope) {
090:   if (*attr != 1)
091:     return -1;
092: 
093:   if (scope != PTHREAD_SCOPE_SYSTEM)
094:     return -1;
095: 
096:   return 0;
097: }
098: 
099: void *(*PLASMA_realThStart)(void *);
100: 
101: /*
102:   This function is only called to have a proxy that is compatible with WINAPI.
103:  */
104: unsigned WINAPI PLASMA_winThStart(void *arg) {
105:   PLASMA_realThStart( arg );
106:   return 0;
107: }
108: 
109: PLASMA_DLLPORT int PLASMA_CDECL pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start) (void *), void *arg) {
110: 
111:   /* this assumes that the threads call the same function, always; it also assumes there
112:      is no race condition while assigning a pointer and using it from within threads
113:      (this assumption is fulfilled by creating the new thread in suspended state) */
114:   PLASMA_realThStart = start;
115: 
116:   thread->hThread = (HANDLE)_beginthreadex(
117:     NULL, /* default security */
118:     0, /* stack size: use the size of calling thread */
119:     PLASMA_winThStart,
120:     arg,
121:     CREATE_SUSPENDED,
122:     /*0,*/   /* the thread will run immedietally (rather than get suspended) */
123:     &thread->uThId );
124: 
125:   /* We need to make sure that _beginthreadex() returns to the parent thread first
126:      so we can safely fill up the members of the pthread_t structure without possible
127:      race conditions. If the new thread is created in supsended state we eliminate
128:      the race condition but now we have to resume the new thread. */
129:   ResumeThread( thread->hThread );
130: 
131:   return 0;
132: }
133: 
134: PLASMA_DLLPORT int PLASMA_CDECL pthread_join(pthread_t thread, void **value_ptr) {
135:   WaitForSingleObject( thread.hThread, INFINITE );
136:   CloseHandle( thread.hThread );
137:   return 0;
138: }
139: 
140: PLASMA_DLLPORT int PLASMA_CDECL pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) {
141:   InitializeCriticalSection( &cond->cs );
142:   cond->hSem = CreateSemaphore( NULL, /* no security attributes */
143:     0, /* initial count */
144:     LONG_MAX, /* maximum count*/
145:     NULL ); /* unnamed semaphore */
146:   cond->hEvt = CreateEvent( NULL, /* no security attributes */
147:     FALSE, /* reset to not-singaled automatically */
148:     FALSE, /* set initial status to not-signaled */
149:     NULL ); /* unnamed event */
150:   cond->waitCount = 0;
151:   return 0;
152: }
153: 
154: PLASMA_DLLPORT int PLASMA_CDECL pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
155:   int last;
156: 
157:   /* Avoid race condition on waiting thread counter. */
158:   EnterCriticalSection(&cond->cs);
159:   cond->waitCount++;
160:   LeaveCriticalSection(&cond->cs);
161: 
162:   /* Releases _atomically_ the mutex and wait on the semaphore until
163:      pthread_cond_signal() or pthread_cond_broadcast() are called (by another thread). */
164:   SignalObjectAndWait(*mutex, cond->hSem, INFINITE, FALSE);
165: 
166:   /* Avoid race condition on waiting thread counter. */
167:   EnterCriticalSection(&cond->cs);
168:   cond->waitCount--; /* this thread doesn't wait any more */
169: 
170:   /* if this is the last thread to have waited */
171:   last = cond->waitCount == 0;
172: 
173:   LeaveCriticalSection(&cond->cs);
174: 
175:   /* If this thread is the last waiter thread during this particular broadcast
176:      then let all the other threads proceed. */
177:   if (last)
178:     /* This call ensures that two things happen atomically: signaling the hEvt event and
179:        waiting until "mutex" can be acquired. */
180:     SignalObjectAndWait(cond->hEvt, *mutex, INFINITE, FALSE);
181:   else
182:     WaitForSingleObject(*mutex, INFINITE); /* Upon return, this thread has to own "mutex". */
183: 
184:   return 0;
185: }
186: 
187: PLASMA_DLLPORT int PLASMA_CDECL pthread_cond_broadcast(pthread_cond_t *cond) {
188:   int more_waiters = 0;
189: 
190:   /* This is needed to ensure exclusive access to "waitCount" */
191:   EnterCriticalSection (&cond->cs);
192: 
193:   if (cond->waitCount > 0) {
194:     /* always are broadcasting - no need for pthread_cond_singal() case */
195:     more_waiters = 1;
196:   }
197: 
198:   if (more_waiters) {
199:     /* this will wake up all the waiters atomically at once. */
200:     ReleaseSemaphore(cond->hSem, cond->waitCount, 0);
201: 
202:     LeaveCriticalSection(&cond->cs);
203: 
204:     /* Wait for all the awakened threads to acquire the counting semaphore. */
205:     WaitForSingleObject(cond->hEvt, INFINITE);
206:   } else
207:     LeaveCriticalSection(&cond->cs);
208: 
209:   return 0;
210: }
211: 
212: int pthread_conclevel;
213: 
214: PLASMA_DLLPORT int PLASMA_CDECL pthread_setconcurrency (int level) {
215:   pthread_conclevel = level;
216:   return 0;
217: }
218: