5 * Copyright 2011 Austin English
6 * Copyright 2012 Dan Kegel
7 * Copyright 2015 Sebastian Lackner
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
32 #include "wine/debug.h"
33 #include "wine/list.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(vcomp
);
37 typedef CRITICAL_SECTION
*omp_lock_t
;
38 typedef CRITICAL_SECTION
*omp_nest_lock_t
;
40 static struct list vcomp_idle_threads
= LIST_INIT(vcomp_idle_threads
);
41 static DWORD vcomp_context_tls
= TLS_OUT_OF_INDEXES
;
42 static HMODULE vcomp_module
;
43 static int vcomp_max_threads
;
44 static int vcomp_num_threads
;
45 static BOOL vcomp_nested_fork
= FALSE
;
47 static RTL_CRITICAL_SECTION vcomp_section
;
48 static RTL_CRITICAL_SECTION_DEBUG critsect_debug
=
51 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
52 0, 0, { (DWORD_PTR
)(__FILE__
": vcomp_section") }
54 static RTL_CRITICAL_SECTION vcomp_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
56 #define VCOMP_DYNAMIC_FLAGS_STATIC 0x01
57 #define VCOMP_DYNAMIC_FLAGS_CHUNKED 0x02
58 #define VCOMP_DYNAMIC_FLAGS_GUIDED 0x03
59 #define VCOMP_DYNAMIC_FLAGS_INCREMENT 0x40
61 struct vcomp_thread_data
63 struct vcomp_team_data
*team
;
64 struct vcomp_task_data
*task
;
69 /* only used for concurrent tasks */
71 CONDITION_VARIABLE cond
;
81 unsigned int dynamic_type
;
82 unsigned int dynamic_begin
;
83 unsigned int dynamic_end
;
86 struct vcomp_team_data
88 CONDITION_VARIABLE cond
;
92 /* callback arguments */
102 struct vcomp_task_data
108 unsigned int section
;
113 unsigned int dynamic
;
114 unsigned int dynamic_first
;
115 unsigned int dynamic_last
;
116 unsigned int dynamic_iterations
;
118 unsigned int dynamic_chunksize
;
121 #if defined(__i386__)
123 extern void CDECL
_vcomp_fork_call_wrapper(void *wrapper
, int nargs
, __ms_va_list args
);
124 __ASM_GLOBAL_FUNC( _vcomp_fork_call_wrapper
,
126 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
127 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
129 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
131 __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
133 __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
134 "movl 12(%ebp),%edx\n\t"
141 "movl 12(%ebp),%ecx\n\t"
142 "movl 16(%ebp),%esi\n\t"
145 "1:\tcall *8(%ebp)\n\t"
146 "leal -8(%ebp),%esp\n\t"
148 __ASM_CFI(".cfi_same_value %edi\n\t")
150 __ASM_CFI(".cfi_same_value %esi\n\t")
152 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
153 __ASM_CFI(".cfi_same_value %ebp\n\t")
156 #elif defined(__x86_64__)
158 extern void CDECL
_vcomp_fork_call_wrapper(void *wrapper
, int nargs
, __ms_va_list args
);
159 __ASM_GLOBAL_FUNC( _vcomp_fork_call_wrapper
,
161 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
162 __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
164 __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
166 __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
168 __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
172 "cmovgq %rdx,%rcx\n\t"
173 "leaq 0(,%rcx,8),%rdx\n\t"
179 "movq 0(%rsp),%rcx\n\t"
180 "movq 8(%rsp),%rdx\n\t"
181 "movq 16(%rsp),%r8\n\t"
182 "movq 24(%rsp),%r9\n\t"
184 "leaq -16(%rbp),%rsp\n\t"
186 __ASM_CFI(".cfi_same_value %rdi\n\t")
188 __ASM_CFI(".cfi_same_value %rsi\n\t")
189 __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
191 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
192 __ASM_CFI(".cfi_same_value %rbp\n\t")
195 #elif defined(__arm__)
197 extern void CDECL
_vcomp_fork_call_wrapper(void *wrapper
, int nargs
, __ms_va_list args
);
198 __ASM_GLOBAL_FUNC( _vcomp_fork_call_wrapper
,
200 "push {r4, r5, LR}\n\t"
208 "subeq SP, SP, #4\n\t"
209 "1:\tsub r3, r3, #4\n\t"
210 "ldr r0, [r2, r3]\n\t"
211 "str r0, [SP, r3]\n\t"
226 "4:\tpop {r0-r3}\n\t"
233 static void CDECL
_vcomp_fork_call_wrapper(void *wrapper
, int nargs
, __ms_va_list args
)
235 ERR("Not implemented for this architecture\n");
240 static inline struct vcomp_thread_data
*vcomp_get_thread_data(void)
242 return (struct vcomp_thread_data
*)TlsGetValue(vcomp_context_tls
);
245 static inline void vcomp_set_thread_data(struct vcomp_thread_data
*thread_data
)
247 TlsSetValue(vcomp_context_tls
, thread_data
);
250 static struct vcomp_thread_data
*vcomp_init_thread_data(void)
252 struct vcomp_thread_data
*thread_data
= vcomp_get_thread_data();
255 struct vcomp_thread_data thread
;
256 struct vcomp_task_data task
;
259 if (thread_data
) return thread_data
;
260 if (!(data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*data
))))
262 ERR("could not create thread data\n");
266 data
->task
.single
= 0;
267 data
->task
.section
= 0;
268 data
->task
.dynamic
= 0;
270 thread_data
= &data
->thread
;
271 thread_data
->team
= NULL
;
272 thread_data
->task
= &data
->task
;
273 thread_data
->thread_num
= 0;
274 thread_data
->parallel
= FALSE
;
275 thread_data
->fork_threads
= 0;
276 thread_data
->single
= 1;
277 thread_data
->section
= 1;
278 thread_data
->dynamic
= 1;
279 thread_data
->dynamic_type
= 0;
281 vcomp_set_thread_data(thread_data
);
285 static void vcomp_free_thread_data(void)
287 struct vcomp_thread_data
*thread_data
= vcomp_get_thread_data();
288 if (!thread_data
) return;
290 HeapFree(GetProcessHeap(), 0, thread_data
);
291 vcomp_set_thread_data(NULL
);
294 void CDECL
_vcomp_atomic_add_i4(int *dest
, int val
)
296 interlocked_xchg_add(dest
, val
);
299 void CDECL
_vcomp_atomic_and_i4(int *dest
, int val
)
302 do old
= *dest
; while (interlocked_cmpxchg(dest
, old
& val
, old
) != old
);
305 void CDECL
_vcomp_atomic_div_i4(int *dest
, int val
)
308 do old
= *dest
; while (interlocked_cmpxchg(dest
, old
/ val
, old
) != old
);
311 void CDECL
_vcomp_atomic_div_ui4(unsigned int *dest
, unsigned int val
)
314 do old
= *dest
; while (interlocked_cmpxchg((int *)dest
, old
/ val
, old
) != old
);
317 void CDECL
_vcomp_atomic_mul_i4(int *dest
, int val
)
320 do old
= *dest
; while (interlocked_cmpxchg(dest
, old
* val
, old
) != old
);
323 void CDECL
_vcomp_atomic_or_i4(int *dest
, int val
)
326 do old
= *dest
; while (interlocked_cmpxchg(dest
, old
| val
, old
) != old
);
329 void CDECL
_vcomp_atomic_shl_i4(int *dest
, int val
)
332 do old
= *dest
; while (interlocked_cmpxchg(dest
, old
<< val
, old
) != old
);
335 void CDECL
_vcomp_atomic_shr_i4(int *dest
, int val
)
338 do old
= *dest
; while (interlocked_cmpxchg(dest
, old
>> val
, old
) != old
);
341 void CDECL
_vcomp_atomic_shr_ui4(unsigned int *dest
, unsigned int val
)
344 do old
= *dest
; while (interlocked_cmpxchg((int *)dest
, old
>> val
, old
) != old
);
347 void CDECL
_vcomp_atomic_sub_i4(int *dest
, int val
)
349 interlocked_xchg_add(dest
, -val
);
352 void CDECL
_vcomp_atomic_xor_i4(int *dest
, int val
)
355 do old
= *dest
; while (interlocked_cmpxchg(dest
, old
^ val
, old
) != old
);
358 void CDECL
_vcomp_atomic_add_r4(float *dest
, float val
)
364 *(float *)&new = *(float *)&old
+ val
;
366 while (interlocked_cmpxchg((int *)dest
, new, old
) != old
);
369 void CDECL
_vcomp_atomic_div_r4(float *dest
, float val
)
375 *(float *)&new = *(float *)&old
/ val
;
377 while (interlocked_cmpxchg((int *)dest
, new, old
) != old
);
380 void CDECL
_vcomp_atomic_mul_r4(float *dest
, float val
)
386 *(float *)&new = *(float *)&old
* val
;
388 while (interlocked_cmpxchg((int *)dest
, new, old
) != old
);
391 void CDECL
_vcomp_atomic_sub_r4(float *dest
, float val
)
397 *(float *)&new = *(float *)&old
- val
;
399 while (interlocked_cmpxchg((int *)dest
, new, old
) != old
);
402 void CDECL
_vcomp_atomic_add_r8(double *dest
, double val
)
407 old
= *(LONG64
*)dest
;
408 *(double *)&new = *(double *)&old
+ val
;
410 while (interlocked_cmpxchg64((LONG64
*)dest
, new, old
) != old
);
413 void CDECL
_vcomp_atomic_div_r8(double *dest
, double val
)
418 old
= *(LONG64
*)dest
;
419 *(double *)&new = *(double *)&old
/ val
;
421 while (interlocked_cmpxchg64((LONG64
*)dest
, new, old
) != old
);
424 void CDECL
_vcomp_atomic_mul_r8(double *dest
, double val
)
429 old
= *(LONG64
*)dest
;
430 *(double *)&new = *(double *)&old
* val
;
432 while (interlocked_cmpxchg64((LONG64
*)dest
, new, old
) != old
);
435 void CDECL
_vcomp_atomic_sub_r8(double *dest
, double val
)
440 old
= *(LONG64
*)dest
;
441 *(double *)&new = *(double *)&old
- val
;
443 while (interlocked_cmpxchg64((LONG64
*)dest
, new, old
) != old
);
446 int CDECL
omp_get_dynamic(void)
452 int CDECL
omp_get_max_threads(void)
455 return vcomp_max_threads
;
458 int CDECL
omp_get_nested(void)
461 return vcomp_nested_fork
;
464 int CDECL
omp_get_num_procs(void)
470 int CDECL
omp_get_num_threads(void)
472 struct vcomp_team_data
*team_data
= vcomp_init_thread_data()->team
;
474 return team_data
? team_data
->num_threads
: 1;
477 int CDECL
omp_get_thread_num(void)
480 return vcomp_init_thread_data()->thread_num
;
483 /* Time in seconds since "some time in the past" */
484 double CDECL
omp_get_wtime(void)
486 return GetTickCount() / 1000.0;
489 void CDECL
omp_set_dynamic(int val
)
491 TRACE("(%d): stub\n", val
);
494 void CDECL
omp_set_nested(int nested
)
496 TRACE("(%d)\n", nested
);
497 vcomp_nested_fork
= (nested
!= 0);
500 void CDECL
omp_set_num_threads(int num_threads
)
502 TRACE("(%d)\n", num_threads
);
503 if (num_threads
>= 1)
504 vcomp_num_threads
= num_threads
;
507 void CDECL
_vcomp_flush(void)
512 void CDECL
_vcomp_barrier(void)
514 struct vcomp_team_data
*team_data
= vcomp_init_thread_data()->team
;
521 EnterCriticalSection(&vcomp_section
);
522 if (++team_data
->barrier_count
>= team_data
->num_threads
)
524 team_data
->barrier
++;
525 team_data
->barrier_count
= 0;
526 WakeAllConditionVariable(&team_data
->cond
);
530 unsigned int barrier
= team_data
->barrier
;
531 while (team_data
->barrier
== barrier
)
532 SleepConditionVariableCS(&team_data
->cond
, &vcomp_section
, INFINITE
);
534 LeaveCriticalSection(&vcomp_section
);
537 void CDECL
_vcomp_set_num_threads(int num_threads
)
539 TRACE("(%d)\n", num_threads
);
540 if (num_threads
>= 1)
541 vcomp_init_thread_data()->fork_threads
= num_threads
;
544 int CDECL
_vcomp_master_begin(void)
547 return !vcomp_init_thread_data()->thread_num
;
550 void CDECL
_vcomp_master_end(void)
553 /* nothing to do here */
556 int CDECL
_vcomp_single_begin(int flags
)
558 struct vcomp_thread_data
*thread_data
= vcomp_init_thread_data();
559 struct vcomp_task_data
*task_data
= thread_data
->task
;
562 TRACE("(%x): semi-stub\n", flags
);
564 EnterCriticalSection(&vcomp_section
);
565 thread_data
->single
++;
566 if ((int)(thread_data
->single
- task_data
->single
) > 0)
568 task_data
->single
= thread_data
->single
;
571 LeaveCriticalSection(&vcomp_section
);
576 void CDECL
_vcomp_single_end(void)
579 /* nothing to do here */
582 void CDECL
_vcomp_sections_init(int n
)
584 struct vcomp_thread_data
*thread_data
= vcomp_init_thread_data();
585 struct vcomp_task_data
*task_data
= thread_data
->task
;
589 EnterCriticalSection(&vcomp_section
);
590 thread_data
->section
++;
591 if ((int)(thread_data
->section
- task_data
->section
) > 0)
593 task_data
->section
= thread_data
->section
;
594 task_data
->num_sections
= n
;
595 task_data
->section_index
= 0;
597 LeaveCriticalSection(&vcomp_section
);
600 int CDECL
_vcomp_sections_next(void)
602 struct vcomp_thread_data
*thread_data
= vcomp_init_thread_data();
603 struct vcomp_task_data
*task_data
= thread_data
->task
;
608 EnterCriticalSection(&vcomp_section
);
609 if (thread_data
->section
== task_data
->section
&&
610 task_data
->section_index
!= task_data
->num_sections
)
612 i
= task_data
->section_index
++;
614 LeaveCriticalSection(&vcomp_section
);
618 void CDECL
_vcomp_for_static_simple_init(unsigned int first
, unsigned int last
, int step
,
619 BOOL increment
, unsigned int *begin
, unsigned int *end
)
621 unsigned int iterations
, per_thread
, remaining
;
622 struct vcomp_thread_data
*thread_data
= vcomp_init_thread_data();
623 struct vcomp_team_data
*team_data
= thread_data
->team
;
624 int num_threads
= team_data
? team_data
->num_threads
: 1;
625 int thread_num
= thread_data
->thread_num
;
627 TRACE("(%u, %u, %d, %u, %p, %p)\n", first
, last
, step
, increment
, begin
, end
);
629 if (num_threads
== 1)
639 *end
= increment
? -1 : 1;
644 iterations
= 1 + (last
- first
) / step
;
647 iterations
= 1 + (first
- last
) / step
;
651 per_thread
= iterations
/ num_threads
;
652 remaining
= iterations
- per_thread
* num_threads
;
654 if (thread_num
< remaining
)
657 first
+= remaining
* step
;
665 *begin
= first
+ per_thread
* thread_num
* step
;
666 *end
= *begin
+ (per_thread
- 1) * step
;
669 void CDECL
_vcomp_for_static_init(int first
, int last
, int step
, int chunksize
, unsigned int *loops
,
670 int *begin
, int *end
, int *next
, int *lastchunk
)
672 unsigned int iterations
, num_chunks
, per_thread
, remaining
;
673 struct vcomp_thread_data
*thread_data
= vcomp_init_thread_data();
674 struct vcomp_team_data
*team_data
= thread_data
->team
;
675 int num_threads
= team_data
? team_data
->num_threads
: 1;
676 int thread_num
= thread_data
->thread_num
;
678 TRACE("(%d, %d, %d, %d, %p, %p, %p, %p, %p)\n",
679 first
, last
, step
, chunksize
, loops
, begin
, end
, next
, lastchunk
);
681 if (num_threads
== 1 && chunksize
!= 1)
693 *loops
= !thread_num
;
711 iterations
= 1 + (last
- first
) / step
;
714 iterations
= 1 + (first
- last
) / step
;
721 num_chunks
= ((DWORD64
)iterations
+ chunksize
- 1) / chunksize
;
722 per_thread
= num_chunks
/ num_threads
;
723 remaining
= num_chunks
- per_thread
* num_threads
;
725 *loops
= per_thread
+ (thread_num
< remaining
);
726 *begin
= first
+ thread_num
* chunksize
* step
;
727 *end
= *begin
+ (chunksize
- 1) * step
;
728 *next
= chunksize
* num_threads
* step
;
729 *lastchunk
= first
+ (num_chunks
- 1) * chunksize
* step
;
732 void CDECL
_vcomp_for_static_end(void)
735 /* nothing to do here */
738 void CDECL
_vcomp_for_dynamic_init(unsigned int flags
, unsigned int first
, unsigned int last
,
739 int step
, unsigned int chunksize
)
741 unsigned int iterations
, per_thread
, remaining
;
742 struct vcomp_thread_data
*thread_data
= vcomp_init_thread_data();
743 struct vcomp_team_data
*team_data
= thread_data
->team
;
744 struct vcomp_task_data
*task_data
= thread_data
->task
;
745 int num_threads
= team_data
? team_data
->num_threads
: 1;
746 int thread_num
= thread_data
->thread_num
;
747 unsigned int type
= flags
& ~VCOMP_DYNAMIC_FLAGS_INCREMENT
;
749 TRACE("(%u, %u, %u, %d, %u)\n", flags
, first
, last
, step
, chunksize
);
753 thread_data
->dynamic_type
= 0;
757 if (flags
& VCOMP_DYNAMIC_FLAGS_INCREMENT
)
758 iterations
= 1 + (last
- first
) / step
;
761 iterations
= 1 + (first
- last
) / step
;
765 if (type
== VCOMP_DYNAMIC_FLAGS_STATIC
)
767 per_thread
= iterations
/ num_threads
;
768 remaining
= iterations
- per_thread
* num_threads
;
770 if (thread_num
< remaining
)
773 first
+= remaining
* step
;
776 thread_data
->dynamic_type
= 0;
780 thread_data
->dynamic_type
= VCOMP_DYNAMIC_FLAGS_STATIC
;
781 thread_data
->dynamic_begin
= first
+ per_thread
* thread_num
* step
;
782 thread_data
->dynamic_end
= thread_data
->dynamic_begin
+ (per_thread
- 1) * step
;
786 if (type
!= VCOMP_DYNAMIC_FLAGS_CHUNKED
&&
787 type
!= VCOMP_DYNAMIC_FLAGS_GUIDED
)
789 FIXME("unsupported flags %u\n", flags
);
790 type
= VCOMP_DYNAMIC_FLAGS_GUIDED
;
793 EnterCriticalSection(&vcomp_section
);
794 thread_data
->dynamic
++;
795 thread_data
->dynamic_type
= type
;
796 if ((int)(thread_data
->dynamic
- task_data
->dynamic
) > 0)
798 task_data
->dynamic
= thread_data
->dynamic
;
799 task_data
->dynamic_first
= first
;
800 task_data
->dynamic_last
= last
;
801 task_data
->dynamic_iterations
= iterations
;
802 task_data
->dynamic_step
= step
;
803 task_data
->dynamic_chunksize
= chunksize
;
805 LeaveCriticalSection(&vcomp_section
);
809 int CDECL
_vcomp_for_dynamic_next(unsigned int *begin
, unsigned int *end
)
811 struct vcomp_thread_data
*thread_data
= vcomp_init_thread_data();
812 struct vcomp_task_data
*task_data
= thread_data
->task
;
813 struct vcomp_team_data
*team_data
= thread_data
->team
;
814 int num_threads
= team_data
? team_data
->num_threads
: 1;
816 TRACE("(%p, %p)\n", begin
, end
);
818 if (thread_data
->dynamic_type
== VCOMP_DYNAMIC_FLAGS_STATIC
)
820 *begin
= thread_data
->dynamic_begin
;
821 *end
= thread_data
->dynamic_end
;
822 thread_data
->dynamic_type
= 0;
825 else if (thread_data
->dynamic_type
== VCOMP_DYNAMIC_FLAGS_CHUNKED
||
826 thread_data
->dynamic_type
== VCOMP_DYNAMIC_FLAGS_GUIDED
)
828 unsigned int iterations
= 0;
829 EnterCriticalSection(&vcomp_section
);
830 if (thread_data
->dynamic
== task_data
->dynamic
&&
831 task_data
->dynamic_iterations
!= 0)
833 iterations
= min(task_data
->dynamic_iterations
, task_data
->dynamic_chunksize
);
834 if (thread_data
->dynamic_type
== VCOMP_DYNAMIC_FLAGS_GUIDED
&&
835 task_data
->dynamic_iterations
> num_threads
* task_data
->dynamic_chunksize
)
837 iterations
= (task_data
->dynamic_iterations
+ num_threads
- 1) / num_threads
;
839 *begin
= task_data
->dynamic_first
;
840 *end
= task_data
->dynamic_first
+ (iterations
- 1) * task_data
->dynamic_step
;
841 task_data
->dynamic_iterations
-= iterations
;
842 task_data
->dynamic_first
+= iterations
* task_data
->dynamic_step
;
843 if (!task_data
->dynamic_iterations
)
844 *end
= task_data
->dynamic_last
;
846 LeaveCriticalSection(&vcomp_section
);
847 return iterations
!= 0;
853 int CDECL
omp_in_parallel(void)
856 return vcomp_init_thread_data()->parallel
;
859 static DWORD WINAPI
_vcomp_fork_worker(void *param
)
861 struct vcomp_thread_data
*thread_data
= param
;
862 vcomp_set_thread_data(thread_data
);
864 TRACE("starting worker thread for %p\n", thread_data
);
866 EnterCriticalSection(&vcomp_section
);
869 struct vcomp_team_data
*team
= thread_data
->team
;
872 LeaveCriticalSection(&vcomp_section
);
873 _vcomp_fork_call_wrapper(team
->wrapper
, team
->nargs
, team
->valist
);
874 EnterCriticalSection(&vcomp_section
);
876 thread_data
->team
= NULL
;
877 list_remove(&thread_data
->entry
);
878 list_add_tail(&vcomp_idle_threads
, &thread_data
->entry
);
879 if (++team
->finished_threads
>= team
->num_threads
)
880 WakeAllConditionVariable(&team
->cond
);
883 if (!SleepConditionVariableCS(&thread_data
->cond
, &vcomp_section
, 5000) &&
884 GetLastError() == ERROR_TIMEOUT
&& !thread_data
->team
)
889 list_remove(&thread_data
->entry
);
890 LeaveCriticalSection(&vcomp_section
);
892 TRACE("terminating worker thread for %p\n", thread_data
);
894 HeapFree(GetProcessHeap(), 0, thread_data
);
895 vcomp_set_thread_data(NULL
);
896 FreeLibraryAndExitThread(vcomp_module
, 0);
900 void WINAPIV
_vcomp_fork(BOOL ifval
, int nargs
, void *wrapper
, ...)
902 struct vcomp_thread_data
*prev_thread_data
= vcomp_init_thread_data();
903 struct vcomp_thread_data thread_data
;
904 struct vcomp_team_data team_data
;
905 struct vcomp_task_data task_data
;
908 TRACE("(%d, %d, %p, ...)\n", ifval
, nargs
, wrapper
);
910 if (prev_thread_data
->parallel
&& !vcomp_nested_fork
)
915 else if (prev_thread_data
->fork_threads
)
916 num_threads
= prev_thread_data
->fork_threads
;
918 num_threads
= vcomp_num_threads
;
920 InitializeConditionVariable(&team_data
.cond
);
921 team_data
.num_threads
= 1;
922 team_data
.finished_threads
= 0;
923 team_data
.nargs
= nargs
;
924 team_data
.wrapper
= wrapper
;
925 __ms_va_start(team_data
.valist
, wrapper
);
926 team_data
.barrier
= 0;
927 team_data
.barrier_count
= 0;
929 task_data
.single
= 0;
930 task_data
.section
= 0;
931 task_data
.dynamic
= 0;
933 thread_data
.team
= &team_data
;
934 thread_data
.task
= &task_data
;
935 thread_data
.thread_num
= 0;
936 thread_data
.parallel
= ifval
|| prev_thread_data
->parallel
;
937 thread_data
.fork_threads
= 0;
938 thread_data
.single
= 1;
939 thread_data
.section
= 1;
940 thread_data
.dynamic
= 1;
941 thread_data
.dynamic_type
= 0;
942 list_init(&thread_data
.entry
);
943 InitializeConditionVariable(&thread_data
.cond
);
948 EnterCriticalSection(&vcomp_section
);
950 /* reuse existing threads (if any) */
951 while (team_data
.num_threads
< num_threads
&& (ptr
= list_head(&vcomp_idle_threads
)))
953 struct vcomp_thread_data
*data
= LIST_ENTRY(ptr
, struct vcomp_thread_data
, entry
);
954 data
->team
= &team_data
;
955 data
->task
= &task_data
;
956 data
->thread_num
= team_data
.num_threads
++;
957 data
->parallel
= thread_data
.parallel
;
958 data
->fork_threads
= 0;
962 data
->dynamic_type
= 0;
963 list_remove(&data
->entry
);
964 list_add_tail(&thread_data
.entry
, &data
->entry
);
965 WakeAllConditionVariable(&data
->cond
);
968 /* spawn additional threads */
969 while (team_data
.num_threads
< num_threads
)
971 struct vcomp_thread_data
*data
;
975 data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*data
));
978 data
->team
= &team_data
;
979 data
->task
= &task_data
;
980 data
->thread_num
= team_data
.num_threads
;
981 data
->parallel
= thread_data
.parallel
;
982 data
->fork_threads
= 0;
986 data
->dynamic_type
= 0;
987 InitializeConditionVariable(&data
->cond
);
989 thread
= CreateThread(NULL
, 0, _vcomp_fork_worker
, data
, 0, NULL
);
992 HeapFree(GetProcessHeap(), 0, data
);
996 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
,
997 (const WCHAR
*)vcomp_module
, &module
);
998 team_data
.num_threads
++;
999 list_add_tail(&thread_data
.entry
, &data
->entry
);
1000 CloseHandle(thread
);
1003 LeaveCriticalSection(&vcomp_section
);
1006 vcomp_set_thread_data(&thread_data
);
1007 _vcomp_fork_call_wrapper(team_data
.wrapper
, team_data
.nargs
, team_data
.valist
);
1008 vcomp_set_thread_data(prev_thread_data
);
1009 prev_thread_data
->fork_threads
= 0;
1011 if (team_data
.num_threads
> 1)
1013 EnterCriticalSection(&vcomp_section
);
1015 team_data
.finished_threads
++;
1016 while (team_data
.finished_threads
< team_data
.num_threads
)
1017 SleepConditionVariableCS(&team_data
.cond
, &vcomp_section
, INFINITE
);
1019 LeaveCriticalSection(&vcomp_section
);
1020 assert(list_empty(&thread_data
.entry
));
1023 __ms_va_end(team_data
.valist
);
1026 static CRITICAL_SECTION
*alloc_critsect(void)
1028 CRITICAL_SECTION
*critsect
;
1029 if (!(critsect
= HeapAlloc(GetProcessHeap(), 0, sizeof(*critsect
))))
1031 ERR("could not allocate critical section\n");
1035 InitializeCriticalSection(critsect
);
1036 critsect
->DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": critsect");
1040 static void destroy_critsect(CRITICAL_SECTION
*critsect
)
1042 if (!critsect
) return;
1043 critsect
->DebugInfo
->Spare
[0] = 0;
1044 DeleteCriticalSection(critsect
);
1045 HeapFree(GetProcessHeap(), 0, critsect
);
1048 static BOOL
critsect_is_locked(CRITICAL_SECTION
*critsect
)
1050 return critsect
->OwningThread
== ULongToHandle(GetCurrentThreadId()) &&
1051 critsect
->RecursionCount
;
1054 void CDECL
omp_init_lock(omp_lock_t
*lock
)
1056 TRACE("(%p)\n", lock
);
1057 *lock
= alloc_critsect();
1060 void CDECL
omp_destroy_lock(omp_lock_t
*lock
)
1062 TRACE("(%p)\n", lock
);
1063 destroy_critsect(*lock
);
1066 void CDECL
omp_set_lock(omp_lock_t
*lock
)
1068 TRACE("(%p)\n", lock
);
1070 if (critsect_is_locked(*lock
))
1072 ERR("omp_set_lock called while holding lock %p\n", *lock
);
1076 EnterCriticalSection(*lock
);
1079 void CDECL
omp_unset_lock(omp_lock_t
*lock
)
1081 TRACE("(%p)\n", lock
);
1082 LeaveCriticalSection(*lock
);
1085 int CDECL
omp_test_lock(omp_lock_t
*lock
)
1087 TRACE("(%p)\n", lock
);
1089 if (critsect_is_locked(*lock
))
1092 return TryEnterCriticalSection(*lock
);
1095 void CDECL
omp_set_nest_lock(omp_nest_lock_t
*lock
)
1097 TRACE("(%p)\n", lock
);
1098 EnterCriticalSection(*lock
);
1101 void CDECL
omp_unset_nest_lock(omp_nest_lock_t
*lock
)
1103 TRACE("(%p)\n", lock
);
1104 LeaveCriticalSection(*lock
);
1107 int CDECL
omp_test_nest_lock(omp_nest_lock_t
*lock
)
1109 TRACE("(%p)\n", lock
);
1110 return TryEnterCriticalSection(*lock
) ? (*lock
)->RecursionCount
: 0;
1113 void CDECL
_vcomp_enter_critsect(CRITICAL_SECTION
**critsect
)
1115 TRACE("(%p)\n", critsect
);
1119 CRITICAL_SECTION
*new_critsect
= alloc_critsect();
1120 if (interlocked_cmpxchg_ptr((void **)critsect
, new_critsect
, NULL
) != NULL
)
1121 destroy_critsect(new_critsect
); /* someone beat us to it */
1124 EnterCriticalSection(*critsect
);
1127 void CDECL
_vcomp_leave_critsect(CRITICAL_SECTION
*critsect
)
1129 TRACE("(%p)\n", critsect
);
1130 LeaveCriticalSection(critsect
);
1133 BOOL WINAPI
DllMain(HINSTANCE instance
, DWORD reason
, LPVOID reserved
)
1135 TRACE("(%p, %d, %p)\n", instance
, reason
, reserved
);
1139 case DLL_WINE_PREATTACH
:
1140 return FALSE
; /* prefer native version */
1142 case DLL_PROCESS_ATTACH
:
1144 SYSTEM_INFO sysinfo
;
1146 if ((vcomp_context_tls
= TlsAlloc()) == TLS_OUT_OF_INDEXES
)
1148 ERR("Failed to allocate TLS index\n");
1152 GetSystemInfo(&sysinfo
);
1153 vcomp_module
= instance
;
1154 vcomp_max_threads
= sysinfo
.dwNumberOfProcessors
;
1155 vcomp_num_threads
= sysinfo
.dwNumberOfProcessors
;
1159 case DLL_PROCESS_DETACH
:
1161 if (reserved
) break;
1162 if (vcomp_context_tls
!= TLS_OUT_OF_INDEXES
)
1164 vcomp_free_thread_data();
1165 TlsFree(vcomp_context_tls
);
1170 case DLL_THREAD_DETACH
:
1172 vcomp_free_thread_data();