; Listing5-5.asm
;
; A program that demonstrates corrects the deadlock.

            option     casemap:none
            option     prologue:none
            include    aoalib.inc   ;AoA library + constants
            includelib aoalib.lib   ;Link in aoalib library
            include    c:\masm32\include64\win64.inc
            include    c:\masm32\include64\kernel32.inc
            includelib c:\masm32\lib64\kernel32.lib  
            
            .const

; Program title:

            align   word
ttlStr      byte    "Listing 5-5", 0

            .data
            align   qword            
Resource1   CRITICAL_SECTION {}
Resource2   CRITICAL_SECTION {}

hEvent1     qword   ?
hEvent2     qword   ?


            .code

saveRBX     textequ <[rbp-8]>

; Here is Thread1:

Thread1     proc    public

            push    rbp
            mov     rbp, rsp
            sub     rsp, 64
            
            mov     saveRBX, rbx
            
            mov     ebx, 100        ;Loop 100 times
rptLoop:    lea     rcx, Resource1
            call    EnterCriticalSection
            
            mov     ecx, 100
            call    Sleep
            
            lea     rcx, Resource2
            call    EnterCriticalSection
            
            mov     edx, ebx
            call    print
            byte    "Thread1: %d", nl, 0
            
            lea     rcx, Resource2
            call    LeaveCriticalSection

            lea     rcx, Resource1
            call    LeaveCriticalSection
            
            dec     ebx
            jnz     rptLoop
            
            mov     rcx, hEvent1    ;Get event handle
            call    SetEvent

; Terminate the thread:

            xor     rax, rax        ;Return result
            mov     rbx, saveRBX
            leave
            ret
Thread1     endp

        

; Here is Thread2. Note that the order of the EnterCriticalSection
; calls have changed from Thread1:

Thread2     proc    public
            push    rbp
            mov     rbp, rsp
            sub     rsp, 64
            
            mov     saveRBX, rbx
            
            mov     ebx, 100        ;Loop 100 times
rptLoop:    
            lea     rcx, Resource1
            call    EnterCriticalSection
            
            mov     ecx, 100
            call    Sleep
            
            lea     rcx, Resource2
            call    EnterCriticalSection
            
            mov     edx, ebx        ;Get thread event
            call    print
            byte    "Thread2: %d", nl, 0
            
            lea     rcx, Resource2
            call    LeaveCriticalSection
            
            lea     rcx, Resource1
            call    LeaveCriticalSection
            
            dec     ebx
            jnz     rptLoop

            mov     rcx, hEvent2    ;Get event handle
            call    SetEvent

; Terminate the thread:

            xor     rax, rax        ;Return result
            mov     rbx, saveRBX
            leave
            ret
Thread2     endp

        
; Here is the main assembly language function.

            
            public  asmMain
asmMain     proc
            
            push    rbp
            mov     rbp, rsp
            sub     rsp, 64
            mov     [rbp-8], rbx
            
; Initialize all the critical sections and events:

            lea     rcx, Resource1
            call    InitializeCriticalSection
            
            lea     rcx, Resource2
            call    InitializeCriticalSection
            
            xor     ecx, ecx        ;No security attributes
            xor     edx, edx        ;Auto-reset mode
            xor     r8d, r8d        ;Initial: unsignaled
            xor     r9, r9          ;No event ID; local
            call    CreateEvent
            mov     hEvent1, rax
                        
            xor     ecx, ecx        ;No security attributes
            xor     edx, edx        ;Auto-reset mode
            xor     r8d, r8d        ;Initial: unsignaled
            xor     r9, r9          ;No event ID; local
            call    CreateEvent
            mov     hEvent2, rax
            
            
; Start the threads running:

            call    print
            byte    "Creating Thread1", nl, 0
            
            xor     rcx, rcx        ;No security attributes
            xor     rdx, rdx        ;Default stack size
            lea     r8, Thread1     ;Address of thread code
            mov     r9, hEvent1     ;Thread parameter
            xor     rax, rax        ;Default thread flags
            mov     [rsp+32], rax   ;Must pass on stack.
            mov     [rsp+40], rax   ;Don't save threadID.
            call    CreateThread
             
            call    print
            byte    "Creating Thread2", nl, 0
            
            xor     rcx, rcx        ;No security attributes
            xor     rdx, rdx        ;Default stack size
            lea     r8, Thread2     ;Address of thread code
            mov     r9, hEvent2     ;Thread parameter
            xor     rax, rax        ;Default thread flags
            mov     [rsp+32], rax   ;Must pass on stack.
            mov     [rsp+40], rax   ;Don't save threadID.
            call    CreateThread
             
; Wait until the two threads complete:

            mov     ecx, 2
            lea     rdx, hEvent1    ;Array of 2 dwords (hEvent1, hEvent2)
            mov     r8d, 1          ;Wait for all signals
            mov     r9d, INFINITE   
            call    WaitForMultipleObjects
            
; Clean up everything:

            lea     rcx, Resource1
            call    DeleteCriticalSection
            
            lea     rcx, Resource2
            call    DeleteCriticalSection
            
            mov     rcx, hEvent1
            call    CloseHandle
            
; Terminate the program.

            mov     rbx, [rbp-8]
            leave
            ret     ;Returns to caller
        
asmMain     endp
            end