Skip to content

Commit

Permalink
[ADDED]Thread.sleep
Browse files Browse the repository at this point in the history
  • Loading branch information
arakov committed Aug 30, 2024
1 parent 04a586e commit be318c6
Show file tree
Hide file tree
Showing 3 changed files with 286 additions and 5 deletions.
277 changes: 277 additions & 0 deletions asm/amd64/corex60.asm
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,280 @@ structure %SYSTEM_ENV
// ; dd ThreadCounter

end

structure %CORE_THREAD_TABLE

dq 0 // ; tt_length : +00h

dq 0 // ; tt_slots : +08h
dq 0

end

// ; --- GC_ALLOC ---
// ; in: ecx - size ; out: ebx - created object
inline % GC_ALLOC

// ; GCXT: set lock
labStart:
mov rdi, data : %CORE_GC_TABLE + gc_lock

labWait:
mov edx, 1
xor eax, eax
lock cmpxchg dword ptr[rdi], edx
jnz short labWait

mov rax, [data : %CORE_GC_TABLE + gc_yg_current]
mov r12, [data : %CORE_GC_TABLE + gc_yg_end]
add rcx, rax
cmp rcx, r12
jae short labYGCollect
mov [data : %CORE_GC_TABLE + gc_yg_current], rcx

// ; GCXT: clear sync field
mov edx, 0FFFFFFFFh
lea rbx, [rax + elObjectOffset]
// ; GCXT: free lock
// ; could we use mov [esi], 0 instead?
lock xadd [rdi], edx

ret

labYGCollect:
// ; save registers
sub rcx, rax
xor edx, edx
call %GC_COLLECT
ret

end

// ; --- GC_COLLECT ---
// ; in: ecx - fullmode (0, 1)
inline % GC_COLLECT

labStart:
// ; GCXT: find the current thread entry
mov rdi, gs:[58h]
mov rax, [data : %CORE_TLS_INDEX]

push r10
push r11

// ; GCXT: find the current thread entry
mov rax, [rdi+rax*8]

push rbp

// ; GCXT: lock frame
// ; get current thread event
mov rsi, [rax + tt_sync_event]
mov [rax + tt_stack_frame], rsp

push rdx
push rcx

// ; === GCXT: safe point ===
mov rdx, [data : %CORE_GC_TABLE + gc_signal]
// ; if it is a collecting thread, starts the GC
test rdx, rdx
jz short labConinue
// ; otherwise eax contains the collecting thread event

// ; signal the collecting thread that it is stopped
push edx
push esi
call extern "$rt.SignalStopGCLA"
add esp, 4

// ; free lock
// ; could we use mov [esi], 0 instead?
mov edi, data : %CORE_GC_TABLE + gc_lock
mov ebx, 0FFFFFFFFh
lock xadd [edi], ebx

// ; stop until GC is ended
call extern "$rt.WaitForSignalGCLA"
add esp, 4

// ; restore registers and try again
pop ecx
pop edx
pop ebp
pop esi

test ecx, ecx
jz labStart

// ; repeat the alloc operation if required
call %GC_ALLOC
ret

labConinue:
mov [data : %CORE_GC_TABLE + gc_signal], esi // set the collecting thread signal
mov ebp, esp

// ; === thread synchronization ===

// ; create list of threads need to be stopped
mov eax, esi
// ; get tls entry address
mov esi, data : %CORE_THREAD_TABLE + tt_slots
xor ecx, ecx
mov edi, [esi - 4]
labNext:
mov edx, [esi]
test edx, edx
jz short labSkipTT
cmp eax, [edx + tt_sync_event]
setz cl
or ecx, [edx + tt_flags]
test ecx, 1
// ; skip current thread signal / thread in safe region from wait list
jnz short labSkipSave
push [edx + tt_sync_event]
labSkipSave:

// ; reset all signal events
push [edx + tt_sync_event]
call extern "$rt.SignalClearGCLA"
add esp, 4

lea esi, [esi + 8]
mov eax, [data : %CORE_GC_TABLE + gc_signal]
labSkipTT:
sub edi, 1
jnz short labNext

mov esi, data : %CORE_GC_TABLE + gc_lock
mov edx, 0FFFFFFFFh
mov ebx, ebp

// ; free lock
// ; could we use mov [esi], 0 instead?
lock xadd [esi], edx

mov ecx, esp
sub ebx, esp
jz short labSkipWait

// ; wait until they all stopped
shr ebx, 2
push ecx
push ebx
call extern "$rt.WaitForSignalsGCLA"

labSkipWait:
// ; remove list
mov esp, ebp

// ==== GCXT end ==============

// ; create set of roots
mov ebp, esp
xor ecx, ecx
push ecx // ; reserve place
push ecx
push ecx

// ; save static roots
mov ecx, [rdata : %SYSTEM_ENV]
mov esi, stat : %0
shl ecx, 2
push esi
push ecx

// ; save perm roots
mov esi, [data : %CORE_GC_TABLE + gc_perm_start]
mov ecx, [data : %CORE_GC_TABLE + gc_perm_current]
sub ecx, esi
push esi
push ecx

// ; == GCXT: save frames ==
mov eax, data : %CORE_THREAD_TABLE
mov ebx, [eax]

labYGNextThread:
sub ebx, 1
mov eax, data : %CORE_THREAD_TABLE + tt_slots
// ; get tls entry address
mov esi, [eax+ebx*8]
test esi, esi
jz short labYGNextThreadSkip

// ; get the thread local roots
lea eax, [esi + tt_size]
mov ecx, [rdata : %SYSTEM_ENV + env_tls_size]
push eax
push ecx

// ; get the top frame pointer
mov eax, [esi + tt_stack_frame]
mov ecx, eax

labYGNextFrame:
mov esi, eax
mov eax, [esi]
test eax, eax
jnz short labYGNextFrame
push ecx
sub ecx, esi
neg ecx
push ecx
mov eax, [esi + 4]
test eax, eax
mov ecx, eax
jnz short labYGNextFrame
nop
nop

labYGNextThreadSkip:
test ebx, ebx
jnz short labYGNextThread
// ; == GCXT: end ==

mov [ebp-4], esp // ; save position for roots

mov ebx, [ebp]
mov edx, [ebp+4]
mov eax, esp

// ; restore frame to correctly display a call stack
mov ecx, ebp
mov ebp, [ecx+8]

// ; call GC routine
push ecx
push edx
push ebx
push eax
call extern "$rt.CollectGCLA"

mov edi, eax
mov ebp, [esp+12]

// ; GCXT: signal the collecting thread that GC is ended
// ; should it be placed into critical section?
xor ecx, ecx
mov esi, [data : %CORE_GC_TABLE + gc_signal]
// ; clear thread signal var
mov [data : %CORE_GC_TABLE + gc_signal], ecx
push esi
call extern "$rt.SignalStopGCLA"

mov ebx, edi

mov esp, ebp
pop ecx
pop edx
pop ebp
pop esi
ret

end
7 changes: 3 additions & 4 deletions doc/todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,24 @@ In development:
=== Iteration 31 (5.9) ===
--------------------------------------
dev:
- thread pool
- async programming (Task, Task<T>, object field (similar to Event), WaitHandle, AsyncLocal<T>, ThreadStatic, ExecutionContext, SynchronizationContext)
- upndown (connector)
- chat: add mutex (see dpa_queue)
- Thread<T> template
- #496
gen:
- lpad : generate a code based on a record
maint:
- #679
- set up automatic tests
port:
- #658 : connect with ldbg from VSCode
prom: posting weekly
--------------------------------------
* x86-64 : mta - test
* x86-64 : mta - corex
* thread pool
* x86-64 : mta - gc_collect
--------------------------------------
* #679
* ThreadLocal<T>

This comment has been minimized.

Copy link
@bencz

bencz Aug 30, 2024

Member

This is like the C# Task ?
Task<T> ?

This comment has been minimized.

Copy link
@arakov

arakov Aug 30, 2024

Author Member

Yes, I'm working on async programming. i will implement similar to C# Task, ThreadPool, ThreadLocal and AsyncLocal
Iterator methods were already implemented in ELENA. But I had to modify them a bit to suit them for async programming.

I'm building base to implement WebApi and so on

This comment has been minimized.

Copy link
@arakov

=== Iteration 32 ===
--------------------------------------
Expand Down
7 changes: 6 additions & 1 deletion src60/system/threading/thread.l
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public sealed class Thread
^ _currentThread
}

static Thread
static Thread Current
{
get()
= _currentThread ?? getCurrentThread();
Expand Down Expand Up @@ -119,4 +119,9 @@ public sealed class Thread

_handle := nil;
}

static sleep(int milliseconds)
{
threadControl.sleep(milliseconds);
}
}

0 comments on commit be318c6

Please sign in to comment.