File: magma_winthread.cpp

package info (click to toggle)
magma 2.9.0%2Bds-2
  • links: PTS, VCS
  • area: contrib
  • in suites: trixie
  • size: 83,212 kB
  • sloc: cpp: 709,115; fortran: 121,916; ansic: 32,343; python: 25,603; f90: 15,208; makefile: 942; xml: 253; csh: 232; sh: 203; perl: 104
file content (307 lines) | stat: -rw-r--r-- 8,951 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/**
 *
 * magma_winthread.cpp
 *
 *  This file handles the mapping from pthreads calls to windows threads.
 *  MAGMA is a software package provided by Univ. of Tennessee,
 *  Univ. of California Berkeley and Univ. of Colorado Denver
 *
 * @version 2.3.1
 * @author Piotr Luszczek
 * @date January 2025
 *
 * This file is originally from PLASMA project, where plasma has been
 * replaced by MAGMA.
 *
 **/
#if defined( _WIN32 ) || defined( _WIN64 )

#include "magma_winthread.h"

#include <limits.h>

/** this is needed to get a declaration for _beginthreadex() */
#include <process.h>

#include <stdio.h>

CRITICAL_SECTION magma_winthread_static_initializer_check_lock;
static int magma_winthread_initialized = 0;

extern "C"
MAGMA_DLLPORT unsigned int MAGMA_CDECL pthread_self_id(void)
{
    return GetCurrentThreadId();
}

extern "C"
MAGMA_DLLPORT pthread_t MAGMA_CDECL pthread_self(void)
{
    pthread_t pt;
    
    pt.hThread = GetCurrentThread();
    pt.uThId = GetCurrentThreadId();
    return pt;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_equal(pthread_t thread1, pthread_t thread2)
{
    if (thread1.uThId == thread2.uThId) // && thread1.hThread == thread2.hThread)
        return 1;
        return 0;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t * attr)
{
    *mutex =
    CreateMutex( NULL,  /** no security atributes */
                 FALSE, /** not owned (initialy) by the creating thread */
                 NULL   /** no name provided: cannot be shared between processes */
    );
    
    return 0;
}

static int pthread_mutex_check_for_static_initialization( pthread_mutex_t *mutex ) {
    int retval = 0;
    /* This should be called once to initialize some structures */
    if ( magma_winthread_initialized == 0 ) {
        magma_winthread_initialized = 1;
        InitializeCriticalSection( &magma_winthread_static_initializer_check_lock );
    }
    EnterCriticalSection( &magma_winthread_static_initializer_check_lock );
    if ( *mutex == PTHREAD_MUTEX_INITIALIZER )
        retval = pthread_mutex_init( mutex, NULL );
    LeaveCriticalSection( &magma_winthread_static_initializer_check_lock );
    return retval;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_mutex_lock(pthread_mutex_t *mutex)
{
    DWORD rv;
    
    if ( *mutex == PTHREAD_MUTEX_INITIALIZER ) pthread_mutex_check_for_static_initialization( mutex );
    rv = WaitForSingleObject( *mutex, INFINITE );
    switch (rv) {
        case WAIT_OBJECT_0: /** the wait was succesful */
            return 0;
        case WAIT_FAILED: /** the wait failed */
            return -1;
        case WAIT_ABANDONED: /** thread killed during the wait */
            return -1;
        case WAIT_TIMEOUT: /** impossible because of INFINITE */
            return -1;
        default:
            return -1;
    }
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_mutex_trylock(pthread_mutex_t *mutex)
{
    DWORD rv;

    if ( *mutex == PTHREAD_MUTEX_INITIALIZER ) pthread_mutex_check_for_static_initialization( mutex );
    rv = WaitForSingleObject( *mutex, 0 );
    switch (rv) {
        case WAIT_OBJECT_0: /** the wait was succesful */
            return 0;
        case WAIT_FAILED: /** the wait failed */
            return -1;
        case WAIT_ABANDONED: /** thread killed during the wait */
            return -1;
        case WAIT_TIMEOUT: /** impossible because of INFINITE */
            return -1;
        default:
            return -1;
    }
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_mutex_unlock(pthread_mutex_t *mutex)
{
    if (! ReleaseMutex( *mutex ))
        return -1;

    return 0;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_mutex_destroy(pthread_mutex_t *mutex)
{
    CloseHandle( *mutex );
    return 0;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_attr_init(pthread_attr_t *attr)
{
    *attr = 1;
    return 0;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_attr_destroy(pthread_attr_t *attr)
{
    *attr = 0;
    return 0;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_attr_setscope(pthread_attr_t *attr, int scope)
{
    if (*attr != 1)
        return -1;

    if (scope != PTHREAD_SCOPE_SYSTEM)
        return -1;

    return 0;
}

void *(*MAGMA_realThStart)(void *);

/*
    This function is only called to have a proxy that is compatible with WINAPI.
 */
unsigned WINAPI MAGMA_winThStart(void *arg) {
    MAGMA_realThStart( arg );
    return 0;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start) (void *), void *arg)
{
    /* this assumes that the threads call the same function, always; it also assumes there
       is no race condition while assigning a pointer and using it from within threads
       (this assumption is fulfilled by creating the new thread in suspended state) */
    MAGMA_realThStart = start;

    thread->hThread = (HANDLE)_beginthreadex(
        NULL, /* default security */
        0, /* stack size: use the size of calling thread */
        MAGMA_winThStart,
        arg,
        CREATE_SUSPENDED,
        /*0,*/     /* the thread will run immedietally (rather than get suspended) */
        &thread->uThId );

    /* We need to make sure that _beginthreadex() returns to the parent thread first
       so we can safely fill up the members of the pthread_t structure without possible
       race conditions. If the new thread is created in supsended state we eliminate
       the race condition but now we have to resume the new thread. */
    ResumeThread( thread->hThread );

    return 0;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_join(pthread_t thread, void **value_ptr)
{
    WaitForSingleObject( thread.hThread, INFINITE );
    CloseHandle( thread.hThread );
    return 0;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
{
    InitializeCriticalSection( &cond->cs );
    cond->hSem = CreateSemaphore( NULL, /* no security attributes */
        0, /* initial count */
        LONG_MAX, /* maximum count*/
        NULL ); /* unnamed semaphore */
    cond->hEvt = CreateEvent( NULL, /* no security attributes */
        FALSE, /* reset to not-singaled automatically */
        FALSE, /* set initial status to not-signaled */
        NULL ); /* unnamed event */
    cond->waitCount = 0;
    return 0;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_cond_destroy(pthread_cond_t *cond)
{
    DeleteCriticalSection( &cond->cs );
    CloseHandle( cond->hSem );
    CloseHandle( cond->hEvt );
    return 0;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
    int last;

    if ( *mutex == PTHREAD_MUTEX_INITIALIZER ) pthread_mutex_check_for_static_initialization( mutex );

    /* Avoid race condition on waiting thread counter. */
    EnterCriticalSection(&cond->cs);
    cond->waitCount++;
    LeaveCriticalSection(&cond->cs);

    /* Releases _atomically_ the mutex and wait on the semaphore until
       pthread_cond_signal() or pthread_cond_broadcast() are called (by another thread). */
    SignalObjectAndWait(*mutex, cond->hSem, INFINITE, FALSE);

    /* Avoid race condition on waiting thread counter. */
    EnterCriticalSection(&cond->cs);
    cond->waitCount--; /* this thread doesn't wait any more */

    /* if this is the last thread to have waited */
    last = cond->waitCount == 0;

    LeaveCriticalSection(&cond->cs);

    /* If this thread is the last waiter thread during this particular broadcast
       then let all the other threads proceed. */
    if (last)
        /* This call ensures that two things happen atomically: signaling the hEvt event and
           waiting until "mutex" can be acquired. */
        SignalObjectAndWait(cond->hEvt, *mutex, INFINITE, FALSE);
    else
        WaitForSingleObject(*mutex, INFINITE); /* Upon return, this thread has to own "mutex". */

    return 0;
}

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_cond_broadcast(pthread_cond_t *cond)
{
    int more_waiters = 0;

    /* This is needed to ensure exclusive access to "waitCount" */
    EnterCriticalSection (&cond->cs);

    if (cond->waitCount > 0) {
        /* always are broadcasting - no need for pthread_cond_singal() case */
        more_waiters = 1;
    }

    if (more_waiters) {
        /* this will wake up all the waiters atomically at once. */
        ReleaseSemaphore(cond->hSem, cond->waitCount, 0);

        LeaveCriticalSection(&cond->cs);

        /* Wait for all the awakened threads to acquire the counting semaphore. */
        WaitForSingleObject(cond->hEvt, INFINITE);
    } else
        LeaveCriticalSection(&cond->cs);

    return 0;
}

int pthread_conclevel;

extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_setconcurrency (int level)
{
    pthread_conclevel = level;
    return 0;
}

#endif /* defined( _WIN32 ) || defined( _WIN64 ) */