2 * Copyright (c) 2002, TransGaming Technologies Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wine/port.h"
24 #include "wine/debug.h"
29 #include "cppexcept.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
38 CRITICAL_SECTION crit
;
41 static LOCKTABLEENTRY lock_table
[ _TOTAL_LOCKS
];
43 static inline void msvcrt_mlock_set_entry_initialized( int locknum
, BOOL initialized
)
45 lock_table
[ locknum
].bInit
= initialized
;
48 static inline void msvcrt_initialize_mlock( int locknum
)
50 InitializeCriticalSection( &(lock_table
[ locknum
].crit
) );
51 lock_table
[ locknum
].crit
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": LOCKTABLEENTRY.crit");
52 msvcrt_mlock_set_entry_initialized( locknum
, TRUE
);
55 static inline void msvcrt_uninitialize_mlock( int locknum
)
57 lock_table
[ locknum
].crit
.DebugInfo
->Spare
[0] = 0;
58 DeleteCriticalSection( &(lock_table
[ locknum
].crit
) );
59 msvcrt_mlock_set_entry_initialized( locknum
, FALSE
);
62 /**********************************************************************
63 * msvcrt_init_mt_locks (internal)
65 * Initialize the table lock. All other locks will be initialized
69 void msvcrt_init_mt_locks(void)
73 TRACE( "initializing mtlocks\n" );
75 /* Initialize the table */
76 for( i
=0; i
< _TOTAL_LOCKS
; i
++ )
78 msvcrt_mlock_set_entry_initialized( i
, FALSE
);
81 /* Initialize our lock table lock */
82 msvcrt_initialize_mlock( _LOCKTAB_LOCK
);
85 /**********************************************************************
88 void CDECL
_lock( int locknum
)
90 TRACE( "(%d)\n", locknum
);
92 /* If the lock doesn't exist yet, create it */
93 if( lock_table
[ locknum
].bInit
== FALSE
)
95 /* Lock while we're changing the lock table */
96 _lock( _LOCKTAB_LOCK
);
98 /* Check again if we've got a bit of a race on lock creation */
99 if( lock_table
[ locknum
].bInit
== FALSE
)
101 TRACE( ": creating lock #%d\n", locknum
);
102 msvcrt_initialize_mlock( locknum
);
105 /* Unlock ourselves */
106 _unlock( _LOCKTAB_LOCK
);
109 EnterCriticalSection( &(lock_table
[ locknum
].crit
) );
112 /**********************************************************************
115 * NOTE: There is no error detection to make sure the lock exists and is acquired.
117 void CDECL
_unlock( int locknum
)
119 TRACE( "(%d)\n", locknum
);
121 LeaveCriticalSection( &(lock_table
[ locknum
].crit
) );
124 #if _MSVCR_VER >= 100
133 typedef void (__cdecl
*yield_func
)(void);
139 SpinWait_state state
;
140 yield_func yield_func
;
143 /* ?_Value@_SpinCount@details@Concurrency@@SAIXZ */
144 unsigned int __cdecl
SpinCount__Value(void)
146 static unsigned int val
= -1;
154 val
= si
.dwNumberOfProcessors
>1 ? 4000 : 0;
160 /* ??0?$_SpinWait@$00@details@Concurrency@@QAE@P6AXXZ@Z */
161 /* ??0?$_SpinWait@$00@details@Concurrency@@QEAA@P6AXXZ@Z */
162 DEFINE_THISCALL_WRAPPER(SpinWait_ctor_yield
, 8)
163 SpinWait
* __thiscall
SpinWait_ctor_yield(SpinWait
*this, yield_func yf
)
165 TRACE("(%p %p)\n", this, yf
);
167 this->state
= SPINWAIT_INIT
;
169 this->yield_func
= yf
;
173 /* ??0?$_SpinWait@$0A@@details@Concurrency@@QAE@P6AXXZ@Z */
174 /* ??0?$_SpinWait@$0A@@details@Concurrency@@QEAA@P6AXXZ@Z */
175 DEFINE_THISCALL_WRAPPER(SpinWait_ctor
, 8)
176 SpinWait
* __thiscall
SpinWait_ctor(SpinWait
*this, yield_func yf
)
178 TRACE("(%p %p)\n", this, yf
);
180 this->state
= SPINWAIT_INIT
;
182 this->yield_func
= yf
;
186 /* ??_F?$_SpinWait@$00@details@Concurrency@@QAEXXZ */
187 /* ??_F?$_SpinWait@$00@details@Concurrency@@QEAAXXZ */
188 /* ??_F?$_SpinWait@$0A@@details@Concurrency@@QAEXXZ */
189 /* ??_F?$_SpinWait@$0A@@details@Concurrency@@QEAAXXZ */
190 DEFINE_THISCALL_WRAPPER(SpinWait_dtor
, 4)
191 void __thiscall
SpinWait_dtor(SpinWait
*this)
193 TRACE("(%p)\n", this);
196 /* ?_DoYield@?$_SpinWait@$00@details@Concurrency@@IAEXXZ */
197 /* ?_DoYield@?$_SpinWait@$00@details@Concurrency@@IEAAXXZ */
198 /* ?_DoYield@?$_SpinWait@$0A@@details@Concurrency@@IAEXXZ */
199 /* ?_DoYield@?$_SpinWait@$0A@@details@Concurrency@@IEAAXXZ */
200 DEFINE_THISCALL_WRAPPER(SpinWait__DoYield
, 4)
201 void __thiscall
SpinWait__DoYield(SpinWait
*this)
203 TRACE("(%p)\n", this);
209 /* ?_NumberOfSpins@?$_SpinWait@$00@details@Concurrency@@IAEKXZ */
210 /* ?_NumberOfSpins@?$_SpinWait@$00@details@Concurrency@@IEAAKXZ */
211 /* ?_NumberOfSpins@?$_SpinWait@$0A@@details@Concurrency@@IAEKXZ */
212 /* ?_NumberOfSpins@?$_SpinWait@$0A@@details@Concurrency@@IEAAKXZ */
213 DEFINE_THISCALL_WRAPPER(SpinWait__NumberOfSpins
, 4)
214 ULONG __thiscall
SpinWait__NumberOfSpins(SpinWait
*this)
216 TRACE("(%p)\n", this);
220 /* ?_SetSpinCount@?$_SpinWait@$00@details@Concurrency@@QAEXI@Z */
221 /* ?_SetSpinCount@?$_SpinWait@$00@details@Concurrency@@QEAAXI@Z */
222 /* ?_SetSpinCount@?$_SpinWait@$0A@@details@Concurrency@@QAEXI@Z */
223 /* ?_SetSpinCount@?$_SpinWait@$0A@@details@Concurrency@@QEAAXI@Z */
224 DEFINE_THISCALL_WRAPPER(SpinWait__SetSpinCount
, 8)
225 void __thiscall
SpinWait__SetSpinCount(SpinWait
*this, unsigned int spin
)
227 TRACE("(%p %d)\n", this, spin
);
230 this->state
= spin
? SPINWAIT_SPIN
: SPINWAIT_YIELD
;
233 /* ?_Reset@?$_SpinWait@$00@details@Concurrency@@IAEXXZ */
234 /* ?_Reset@?$_SpinWait@$00@details@Concurrency@@IEAAXXZ */
235 /* ?_Reset@?$_SpinWait@$0A@@details@Concurrency@@IAEXXZ */
236 /* ?_Reset@?$_SpinWait@$0A@@details@Concurrency@@IEAAXXZ */
237 DEFINE_THISCALL_WRAPPER(SpinWait__Reset
, 4)
238 void __thiscall
SpinWait__Reset(SpinWait
*this)
240 SpinWait__SetSpinCount(this, SpinCount__Value());
243 /* ?_ShouldSpinAgain@?$_SpinWait@$00@details@Concurrency@@IAE_NXZ */
244 /* ?_ShouldSpinAgain@?$_SpinWait@$00@details@Concurrency@@IEAA_NXZ */
245 /* ?_ShouldSpinAgain@?$_SpinWait@$0A@@details@Concurrency@@IAE_NXZ */
246 /* ?_ShouldSpinAgain@?$_SpinWait@$0A@@details@Concurrency@@IEAA_NXZ */
247 DEFINE_THISCALL_WRAPPER(SpinWait__ShouldSpinAgain
, 4)
248 MSVCRT_bool __thiscall
SpinWait__ShouldSpinAgain(SpinWait
*this)
250 TRACE("(%p)\n", this);
253 return this->spin
> 0;
256 /* ?_SpinOnce@?$_SpinWait@$00@details@Concurrency@@QAE_NXZ */
257 /* ?_SpinOnce@?$_SpinWait@$00@details@Concurrency@@QEAA_NXZ */
258 /* ?_SpinOnce@?$_SpinWait@$0A@@details@Concurrency@@QAE_NXZ */
259 /* ?_SpinOnce@?$_SpinWait@$0A@@details@Concurrency@@QEAA_NXZ */
260 DEFINE_THISCALL_WRAPPER(SpinWait__SpinOnce
, 4)
261 MSVCRT_bool __thiscall
SpinWait__SpinOnce(SpinWait
*this)
263 switch(this->state
) {
265 SpinWait__Reset(this);
269 __asm__
__volatile__( "rep;nop" : : : "memory" );
271 __asm__
__volatile__( "" : : : "memory" );
276 this->state
= this->unknown
? SPINWAIT_YIELD
: SPINWAIT_DONE
;
279 this->state
= SPINWAIT_DONE
;
283 SpinWait__Reset(this);
288 static HANDLE keyed_event
;
290 /* keep in sync with msvcp90/msvcp90.h */
291 typedef struct cs_queue
293 struct cs_queue
*next
;
294 #if _MSVCR_VER >= 110
302 ULONG_PTR unk_thread_id
;
304 #if _MSVCR_VER >= 110
313 /* ??0critical_section@Concurrency@@QAE@XZ */
314 /* ??0critical_section@Concurrency@@QEAA@XZ */
315 DEFINE_THISCALL_WRAPPER(critical_section_ctor
, 4)
316 critical_section
* __thiscall
critical_section_ctor(critical_section
*this)
318 TRACE("(%p)\n", this);
323 NtCreateKeyedEvent(&event
, GENERIC_READ
|GENERIC_WRITE
, NULL
, 0);
324 if(InterlockedCompareExchangePointer(&keyed_event
, event
, NULL
) != NULL
)
328 this->unk_thread_id
= 0;
329 this->head
= this->tail
= NULL
;
333 /* ??1critical_section@Concurrency@@QAE@XZ */
334 /* ??1critical_section@Concurrency@@QEAA@XZ */
335 DEFINE_THISCALL_WRAPPER(critical_section_dtor
, 4)
336 void __thiscall
critical_section_dtor(critical_section
*this)
338 TRACE("(%p)\n", this);
341 static void __cdecl
spin_wait_yield(void)
346 static inline void spin_wait_for_next_cs(cs_queue
*q
)
352 SpinWait_ctor(&sw
, &spin_wait_yield
);
353 SpinWait__Reset(&sw
);
355 SpinWait__SpinOnce(&sw
);
359 static inline void cs_set_head(critical_section
*cs
, cs_queue
*q
)
361 cs
->unk_thread_id
= GetCurrentThreadId();
362 cs
->unk_active
.next
= q
->next
;
363 cs
->head
= &cs
->unk_active
;
366 /* ?lock@critical_section@Concurrency@@QAEXXZ */
367 /* ?lock@critical_section@Concurrency@@QEAAXXZ */
368 DEFINE_THISCALL_WRAPPER(critical_section_lock
, 4)
369 void __thiscall
critical_section_lock(critical_section
*this)
373 TRACE("(%p)\n", this);
375 if(this->unk_thread_id
== GetCurrentThreadId()) {
376 FIXME("throw exception\n");
380 memset(&q
, 0, sizeof(q
));
381 last
= InterlockedExchangePointer(&this->tail
, &q
);
384 NtWaitForKeyedEvent(keyed_event
, &q
, 0, NULL
);
387 cs_set_head(this, &q
);
388 if(InterlockedCompareExchangePointer(&this->tail
, &this->unk_active
, &q
) != &q
) {
389 spin_wait_for_next_cs(&q
);
390 this->unk_active
.next
= q
.next
;
394 /* ?try_lock@critical_section@Concurrency@@QAE_NXZ */
395 /* ?try_lock@critical_section@Concurrency@@QEAA_NXZ */
396 DEFINE_THISCALL_WRAPPER(critical_section_try_lock
, 4)
397 MSVCRT_bool __thiscall
critical_section_try_lock(critical_section
*this)
401 TRACE("(%p)\n", this);
403 if(this->unk_thread_id
== GetCurrentThreadId()) {
404 FIXME("throw exception\n");
408 memset(&q
, 0, sizeof(q
));
409 if(!InterlockedCompareExchangePointer(&this->tail
, &q
, NULL
)) {
410 cs_set_head(this, &q
);
411 if(InterlockedCompareExchangePointer(&this->tail
, &this->unk_active
, &q
) != &q
) {
412 spin_wait_for_next_cs(&q
);
413 this->unk_active
.next
= q
.next
;
420 /* ?unlock@critical_section@Concurrency@@QAEXXZ */
421 /* ?unlock@critical_section@Concurrency@@QEAAXXZ */
422 DEFINE_THISCALL_WRAPPER(critical_section_unlock
, 4)
423 void __thiscall
critical_section_unlock(critical_section
*this)
425 TRACE("(%p)\n", this);
427 this->unk_thread_id
= 0;
429 if(InterlockedCompareExchangePointer(&this->tail
, NULL
, &this->unk_active
)
430 == &this->unk_active
) return;
431 spin_wait_for_next_cs(&this->unk_active
);
433 #if _MSVCR_VER >= 110
437 if(!InterlockedExchange(&this->unk_active
.next
->free
, TRUE
))
440 next
= this->unk_active
.next
;
441 if(InterlockedCompareExchangePointer(&this->tail
, NULL
, next
) == next
) {
442 HeapFree(GetProcessHeap(), 0, next
);
445 spin_wait_for_next_cs(next
);
447 this->unk_active
.next
= next
->next
;
448 HeapFree(GetProcessHeap(), 0, next
);
452 NtReleaseKeyedEvent(keyed_event
, this->unk_active
.next
, 0, NULL
);
455 /* ?native_handle@critical_section@Concurrency@@QAEAAV12@XZ */
456 /* ?native_handle@critical_section@Concurrency@@QEAAAEAV12@XZ */
457 DEFINE_THISCALL_WRAPPER(critical_section_native_handle
, 4)
458 critical_section
* __thiscall
critical_section_native_handle(critical_section
*this)
460 TRACE("(%p)\n", this);
464 #if _MSVCR_VER >= 110
465 /* ?try_lock_for@critical_section@Concurrency@@QAE_NI@Z */
466 /* ?try_lock_for@critical_section@Concurrency@@QEAA_NI@Z */
467 DEFINE_THISCALL_WRAPPER(critical_section_try_lock_for
, 8)
468 MSVCRT_bool __thiscall
critical_section_try_lock_for(
469 critical_section
*this, unsigned int timeout
)
473 TRACE("(%p %d)\n", this, timeout
);
475 if(this->unk_thread_id
== GetCurrentThreadId()) {
476 FIXME("throw exception\n");
480 if(!(q
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*q
))))
481 return critical_section_try_lock(this);
483 last
= InterlockedExchangePointer(&this->tail
, q
);
490 GetSystemTimeAsFileTime(&ft
);
491 to
.QuadPart
= ((LONGLONG
)ft
.dwHighDateTime
<<32) +
492 ft
.dwLowDateTime
+ (LONGLONG
)timeout
*10000;
493 status
= NtWaitForKeyedEvent(keyed_event
, q
, 0, &to
);
494 if(status
== STATUS_TIMEOUT
) {
495 if(!InterlockedExchange(&q
->free
, TRUE
))
497 /* A thread has signaled the event and is block waiting. */
498 /* We need to catch the event to wake the thread. */
499 NtWaitForKeyedEvent(keyed_event
, q
, 0, NULL
);
503 cs_set_head(this, q
);
504 if(InterlockedCompareExchangePointer(&this->tail
, &this->unk_active
, q
) != q
) {
505 spin_wait_for_next_cs(q
);
506 this->unk_active
.next
= q
->next
;
509 HeapFree(GetProcessHeap(), 0, q
);
516 critical_section
*cs
;
519 } critical_section_scoped_lock
;
521 /* ??0scoped_lock@critical_section@Concurrency@@QAE@AAV12@@Z */
522 /* ??0scoped_lock@critical_section@Concurrency@@QEAA@AEAV12@@Z */
523 DEFINE_THISCALL_WRAPPER(critical_section_scoped_lock_ctor
, 8)
524 critical_section_scoped_lock
* __thiscall
critical_section_scoped_lock_ctor(
525 critical_section_scoped_lock
*this, critical_section
*cs
)
527 TRACE("(%p %p)\n", this, cs
);
529 critical_section_lock(this->cs
);
533 /* ??1scoped_lock@critical_section@Concurrency@@QAE@XZ */
534 /* ??1scoped_lock@critical_section@Concurrency@@QEAA@XZ */
535 DEFINE_THISCALL_WRAPPER(critical_section_scoped_lock_dtor
, 4)
536 void __thiscall
critical_section_scoped_lock_dtor(critical_section_scoped_lock
*this)
538 TRACE("(%p)\n", this);
539 critical_section_unlock(this->cs
);
542 /* ?_GetConcurrency@details@Concurrency@@YAIXZ */
543 unsigned int __cdecl
_GetConcurrency(void)
545 static unsigned int val
= -1;
553 val
= si
.dwNumberOfProcessors
;
561 #if _MSVCR_VER >= 110
562 typedef struct cv_queue
{
563 struct cv_queue
*next
;
568 /* cv_queue structure is not binary compatible */
570 critical_section lock
;
571 } _Condition_variable
;
573 /* ??0_Condition_variable@details@Concurrency@@QAE@XZ */
574 /* ??0_Condition_variable@details@Concurrency@@QEAA@XZ */
575 DEFINE_THISCALL_WRAPPER(_Condition_variable_ctor
, 4)
576 _Condition_variable
* __thiscall
_Condition_variable_ctor(_Condition_variable
*this)
578 TRACE("(%p)\n", this);
581 critical_section_ctor(&this->lock
);
585 /* ??1_Condition_variable@details@Concurrency@@QAE@XZ */
586 /* ??1_Condition_variable@details@Concurrency@@QEAA@XZ */
587 DEFINE_THISCALL_WRAPPER(_Condition_variable_dtor
, 4)
588 void __thiscall
_Condition_variable_dtor(_Condition_variable
*this)
590 TRACE("(%p)\n", this);
593 cv_queue
*next
= this->queue
->next
;
594 if(!this->queue
->expired
)
595 ERR("there's an active wait\n");
596 HeapFree(GetProcessHeap(), 0, this->queue
);
599 critical_section_dtor(&this->lock
);
602 /* ?wait@_Condition_variable@details@Concurrency@@QAEXAAVcritical_section@3@@Z */
603 /* ?wait@_Condition_variable@details@Concurrency@@QEAAXAEAVcritical_section@3@@Z */
604 DEFINE_THISCALL_WRAPPER(_Condition_variable_wait
, 8)
605 void __thiscall
_Condition_variable_wait(_Condition_variable
*this, critical_section
*cs
)
609 TRACE("(%p, %p)\n", this, cs
);
611 critical_section_lock(&this->lock
);
612 q
.next
= this->queue
;
615 critical_section_unlock(&this->lock
);
617 critical_section_unlock(cs
);
618 NtWaitForKeyedEvent(keyed_event
, &q
, 0, NULL
);
619 critical_section_lock(cs
);
622 /* ?wait_for@_Condition_variable@details@Concurrency@@QAE_NAAVcritical_section@3@I@Z */
623 /* ?wait_for@_Condition_variable@details@Concurrency@@QEAA_NAEAVcritical_section@3@I@Z */
624 DEFINE_THISCALL_WRAPPER(_Condition_variable_wait_for
, 12)
625 MSVCRT_bool __thiscall
_Condition_variable_wait_for(_Condition_variable
*this,
626 critical_section
*cs
, unsigned int timeout
)
633 TRACE("(%p %p %d)\n", this, cs
, timeout
);
635 if(!(q
= HeapAlloc(GetProcessHeap(), 0, sizeof(cv_queue
)))) {
636 throw_bad_alloc("bad allocation");
639 critical_section_lock(&this->lock
);
640 q
->next
= this->queue
;
643 critical_section_unlock(&this->lock
);
645 critical_section_unlock(cs
);
647 GetSystemTimeAsFileTime(&ft
);
648 to
.QuadPart
= ((LONGLONG
)ft
.dwHighDateTime
<< 32) +
649 ft
.dwLowDateTime
+ (LONGLONG
)timeout
* 10000;
650 status
= NtWaitForKeyedEvent(keyed_event
, q
, 0, &to
);
651 if(status
== STATUS_TIMEOUT
) {
652 if(!InterlockedExchange(&q
->expired
, TRUE
)) {
653 critical_section_lock(cs
);
657 NtWaitForKeyedEvent(keyed_event
, q
, 0, 0);
660 HeapFree(GetProcessHeap(), 0, q
);
661 critical_section_lock(cs
);
665 /* ?notify_one@_Condition_variable@details@Concurrency@@QAEXXZ */
666 /* ?notify_one@_Condition_variable@details@Concurrency@@QEAAXXZ */
667 DEFINE_THISCALL_WRAPPER(_Condition_variable_notify_one
, 4)
668 void __thiscall
_Condition_variable_notify_one(_Condition_variable
*this)
672 TRACE("(%p)\n", this);
678 critical_section_lock(&this->lock
);
681 critical_section_unlock(&this->lock
);
684 this->queue
= node
->next
;
685 critical_section_unlock(&this->lock
);
687 if(!InterlockedExchange(&node
->expired
, TRUE
)) {
688 NtReleaseKeyedEvent(keyed_event
, node
, 0, NULL
);
691 HeapFree(GetProcessHeap(), 0, node
);
696 /* ?notify_all@_Condition_variable@details@Concurrency@@QAEXXZ */
697 /* ?notify_all@_Condition_variable@details@Concurrency@@QEAAXXZ */
698 DEFINE_THISCALL_WRAPPER(_Condition_variable_notify_all
, 4)
699 void __thiscall
_Condition_variable_notify_all(_Condition_variable
*this)
703 TRACE("(%p)\n", this);
708 critical_section_lock(&this->lock
);
711 critical_section_unlock(&this->lock
);
714 cv_queue
*next
= ptr
->next
;
716 if(!InterlockedExchange(&ptr
->expired
, TRUE
))
717 NtReleaseKeyedEvent(keyed_event
, ptr
, 0, NULL
);
719 HeapFree(GetProcessHeap(), 0, ptr
);
725 #if _MSVCR_VER >= 100
726 typedef struct rwl_queue
728 struct rwl_queue
*next
;
731 #define WRITER_WAITING 0x80000000
732 /* FIXME: reader_writer_lock structure is not binary compatible
733 * it can't exceed 28/56 bytes */
739 rwl_queue
*writer_head
;
740 rwl_queue
*writer_tail
;
741 rwl_queue
*reader_head
;
742 } reader_writer_lock
;
744 /* ??0reader_writer_lock@Concurrency@@QAE@XZ */
745 /* ??0reader_writer_lock@Concurrency@@QEAA@XZ */
746 DEFINE_THISCALL_WRAPPER(reader_writer_lock_ctor
, 4)
747 reader_writer_lock
* __thiscall
reader_writer_lock_ctor(reader_writer_lock
*this)
749 TRACE("(%p)\n", this);
754 NtCreateKeyedEvent(&event
, GENERIC_READ
|GENERIC_WRITE
, NULL
, 0);
755 if (InterlockedCompareExchangePointer(&keyed_event
, event
, NULL
) != NULL
)
759 memset(this, 0, sizeof(*this));
763 /* ??1reader_writer_lock@Concurrency@@QAE@XZ */
764 /* ??1reader_writer_lock@Concurrency@@QEAA@XZ */
765 DEFINE_THISCALL_WRAPPER(reader_writer_lock_dtor
, 4)
766 void __thiscall
reader_writer_lock_dtor(reader_writer_lock
*this)
768 TRACE("(%p)\n", this);
770 if (this->thread_id
!= 0 || this->count
)
771 WARN("destroying locked reader_writer_lock\n");
774 static inline void spin_wait_for_next_rwl(rwl_queue
*q
)
780 SpinWait_ctor(&sw
, &spin_wait_yield
);
781 SpinWait__Reset(&sw
);
783 SpinWait__SpinOnce(&sw
);
787 /* Remove when proper InterlockedOr implementation is added to wine */
788 static LONG
InterlockedOr(LONG
*d
, LONG v
)
791 while (~(l
= *d
) & v
)
792 if (InterlockedCompareExchange(d
, l
|v
, l
) == l
) break;
796 static LONG
InterlockedAnd(LONG
*d
, LONG v
)
799 while ((l
& v
) != l
) {
800 if((old
= InterlockedCompareExchange(d
, l
&v
, l
)) == l
) break;
806 /* ?lock@reader_writer_lock@Concurrency@@QAEXXZ */
807 /* ?lock@reader_writer_lock@Concurrency@@QEAAXXZ */
808 DEFINE_THISCALL_WRAPPER(reader_writer_lock_lock
, 4)
809 void __thiscall
reader_writer_lock_lock(reader_writer_lock
*this)
811 rwl_queue q
= { NULL
}, *last
;
813 TRACE("(%p)\n", this);
815 if (this->thread_id
== GetCurrentThreadId())
816 FIXME("throw improper_lock exception\n");
818 last
= InterlockedExchangePointer((void**)&this->writer_tail
, &q
);
821 NtWaitForKeyedEvent(keyed_event
, &q
, 0, NULL
);
823 this->writer_head
= &q
;
824 if (InterlockedOr(&this->count
, WRITER_WAITING
))
825 NtWaitForKeyedEvent(keyed_event
, &q
, 0, NULL
);
828 this->thread_id
= GetCurrentThreadId();
829 this->writer_head
= &this->active
;
830 this->active
.next
= NULL
;
831 if (InterlockedCompareExchangePointer((void**)&this->writer_tail
, &this->active
, &q
) != &q
) {
832 spin_wait_for_next_rwl(&q
);
833 this->active
.next
= q
.next
;
837 /* ?lock_read@reader_writer_lock@Concurrency@@QAEXXZ */
838 /* ?lock_read@reader_writer_lock@Concurrency@@QEAAXXZ */
839 DEFINE_THISCALL_WRAPPER(reader_writer_lock_lock_read
, 4)
840 void __thiscall
reader_writer_lock_lock_read(reader_writer_lock
*this)
844 TRACE("(%p)\n", this);
846 if (this->thread_id
== GetCurrentThreadId())
847 FIXME("throw improper_lock exception\n");
850 q
.next
= this->reader_head
;
851 } while(InterlockedCompareExchangePointer((void**)&this->reader_head
, &q
, q
.next
) != q
.next
);
857 while (!((count
= this->count
) & WRITER_WAITING
))
858 if (InterlockedCompareExchange(&this->count
, count
+1, count
) == count
) break;
860 if (count
& WRITER_WAITING
)
861 NtWaitForKeyedEvent(keyed_event
, &q
, 0, NULL
);
863 head
= InterlockedExchangePointer((void**)&this->reader_head
, NULL
);
864 while(head
&& head
!= &q
) {
865 rwl_queue
*next
= head
->next
;
866 InterlockedIncrement(&this->count
);
867 NtReleaseKeyedEvent(keyed_event
, head
, 0, NULL
);
871 NtWaitForKeyedEvent(keyed_event
, &q
, 0, NULL
);
875 /* ?try_lock@reader_writer_lock@Concurrency@@QAE_NXZ */
876 /* ?try_lock@reader_writer_lock@Concurrency@@QEAA_NXZ */
877 DEFINE_THISCALL_WRAPPER(reader_writer_lock_try_lock
, 4)
878 MSVCRT_bool __thiscall
reader_writer_lock_try_lock(reader_writer_lock
*this)
880 rwl_queue q
= { NULL
};
882 TRACE("(%p)\n", this);
884 if (this->thread_id
== GetCurrentThreadId())
885 FIXME("throw improper_lock exception\n");
887 if (InterlockedCompareExchangePointer((void**)&this->writer_tail
, &q
, NULL
))
889 this->writer_head
= &q
;
890 if (!InterlockedCompareExchange(&this->count
, WRITER_WAITING
, 0)) {
891 this->thread_id
= GetCurrentThreadId();
892 this->writer_head
= &this->active
;
893 this->active
.next
= NULL
;
894 if (InterlockedCompareExchangePointer((void**)&this->writer_tail
, &this->active
, &q
) != &q
) {
895 spin_wait_for_next_rwl(&q
);
896 this->active
.next
= q
.next
;
901 if (InterlockedCompareExchangePointer((void**)&this->writer_tail
, NULL
, &q
) == &q
)
903 spin_wait_for_next_rwl(&q
);
904 this->writer_head
= q
.next
;
905 if (!InterlockedOr(&this->count
, WRITER_WAITING
)) {
906 this->thread_id
= GetCurrentThreadId();
907 this->writer_head
= &this->active
;
908 this->active
.next
= q
.next
;
914 /* ?try_lock_read@reader_writer_lock@Concurrency@@QAE_NXZ */
915 /* ?try_lock_read@reader_writer_lock@Concurrency@@QEAA_NXZ */
916 DEFINE_THISCALL_WRAPPER(reader_writer_lock_try_lock_read
, 4)
917 MSVCRT_bool __thiscall
reader_writer_lock_try_lock_read(reader_writer_lock
*this)
921 TRACE("(%p)\n", this);
923 while (!((count
= this->count
) & WRITER_WAITING
))
924 if (InterlockedCompareExchange(&this->count
, count
+1, count
) == count
) return TRUE
;
928 /* ?unlock@reader_writer_lock@Concurrency@@QAEXXZ */
929 /* ?unlock@reader_writer_lock@Concurrency@@QEAAXXZ */
930 DEFINE_THISCALL_WRAPPER(reader_writer_lock_unlock
, 4)
931 void __thiscall
reader_writer_lock_unlock(reader_writer_lock
*this)
934 rwl_queue
*head
, *next
;
936 TRACE("(%p)\n", this);
938 if ((count
= this->count
) & ~WRITER_WAITING
) {
939 count
= InterlockedDecrement(&this->count
);
940 if (count
!= WRITER_WAITING
)
942 NtReleaseKeyedEvent(keyed_event
, this->writer_head
, 0, NULL
);
947 next
= this->writer_head
->next
;
949 NtReleaseKeyedEvent(keyed_event
, next
, 0, NULL
);
952 InterlockedAnd(&this->count
, ~WRITER_WAITING
);
953 head
= InterlockedExchangePointer((void**)&this->reader_head
, NULL
);
956 InterlockedIncrement(&this->count
);
957 NtReleaseKeyedEvent(keyed_event
, head
, 0, NULL
);
961 if (InterlockedCompareExchangePointer((void**)&this->writer_tail
, NULL
, this->writer_head
) == this->writer_head
)
963 InterlockedOr(&this->count
, WRITER_WAITING
);
967 /**********************************************************************
968 * msvcrt_free_locks (internal)
970 * Uninitialize all mt locks. Assume that neither _lock or _unlock will
971 * be called once we're calling this routine (ie _LOCKTAB_LOCK can be deleted)
974 void msvcrt_free_locks(void)
978 TRACE( ": uninitializing all mtlocks\n" );
980 /* Uninitialize the table */
981 for( i
=0; i
< _TOTAL_LOCKS
; i
++ )
983 if( lock_table
[ i
].bInit
)
985 msvcrt_uninitialize_mlock( i
);
989 #if _MSVCR_VER >= 100
991 NtClose(keyed_event
);