FlashBurn
Joined: 06 Jan 2005
Posts: 87
|
I have a problem with my semphores and the scheduler! I have 3 threads to test my semaphores. Every thread wants to print a number and I use a semaphore to protect the print function. I will post the code for my scheduler and the code for the semaphores.
mutex:
;----------------------------
proc mutex_acquire, mut
;----------------------------
begin
mov eax,1
mov esi,[mut]
;----------------------------
align 4
.loop:
xchg [esi],eax
test eax,eax
jz .end
or dword[scheduler_flags],scheduler_reschedule
hlt
; int 20h
mov eax,1
jmp .loop
;----------------------------
align 4
.end:
cli
return
endp
;----------------------------
;----------------------------
proc mutex_release, mut
;----------------------------
begin
mov esi,[mut]
xor eax,eax
xchg [esi],eax
sti
return
endp
;----------------------------
semaphore:
;----------------------------
proc semaphore_acquire, sem
;----------------------------
begin
;----------------------------
; make sure we are the only one to work on the semaphore
call mutex_acquire, dword[sem]
sub dword[esi+semaphore_t.count],1
;----------------------------
; look if we have to wait or we can go right away
mov eax,[esi+semaphore_t.count]
cmp eax,0
jge .end
;----------------------------
; we have to wait
mov edi,[esi+semaphore_t.end]
mov eax,[schdl_act_thread]
test edi,edi
jz .first
xor ebx,ebx
mov [edi+thread_t.next],eax
mov [eax+thread_t.prev],edi
mov [eax+thread_t.next],ebx
mov [esi+semaphore_t.end],eax
jmp .scheduler
;----------------------------
; we are the first thread
align 4
.first:
mov [esi+semaphore_t.start],eax
mov [esi+semaphore_t.end],eax
mov [eax+thread_t.prev],edi
mov [eax+thread_t.next],edi
;----------------------------
; scheduler have to know that this thread wants to wait
.scheduler:
or dword[eax+thread_t.flags],thread_wait
or dword[scheduler_flags],scheduler_reschedule
call mutex_release, dword[sem]
hlt
; int 20h
.end_wait:
return
;----------------------------
align 4
.end:
call mutex_release, dword[sem]
return
endp
;----------------------------
;----------------------------
proc semaphore_release, sem
;----------------------------
begin
;----------------------------
; make sure we are the only one to work on the semaphore
call mutex_acquire, dword[sem]
add dword[esi+semaphore_t.count],1
;----------------------------
; look if we need to awake a thread
mov eax,[esi+semaphore_t.count]
cmp eax,0
jg .end
;----------------------------
; we have to awake the thread on the top of the queue
mov eax,[esi+semaphore_t.start]
mov ebx,[eax+thread_t.next]
xor ecx,ecx
test ebx,ebx
jz .last
mov [ebx+thread_t.prev],ecx
mov [esi+semaphore_t.start],ebx
mov [eax+thread_t.prev],ecx
mov [eax+thread_t.next],ecx
jmp .scheduler
;----------------------------
; there is only one thread on the queue
align 4
.last:
mov [esi+semaphore_t.start],ebx
mov [esi+semaphore_t.end],ebx
mov [eax+thread_t.prev],ebx
mov [eax+thread_t.next],ebx
;----------------------------
; scheduler needs to awaken the thread in eax
.scheduler:
and dword[eax+thread_t.flags],not thread_wait
push eax
call mutex_release, dword[sem]
call scheduler_add_scheduler ;par is in pushed eax
;----------------------------
.end_awaken:
return
;----------------------------
align 4
.end:
call mutex_release, dword[sem]
return
endp
;----------------------------
scheduler:
;----------------------------
proc scheduler_intel
;----------------------------
begin_irq
;----------------------------
; move the ptr of the act thrad into eax
mov eax,[schdl_act_thread]
;----------------------------
; update timer var
add dword[timer_count],1
adc dword[timer_count+4],0
;----------------------------
; check if we need to reschedule
test dword[scheduler_flags],scheduler_reschedule
jne .next_thread
;----------------------------
; check if the thread has more time 2 run
sub dword[eax+thread_t.time2run],1
jz .next_thread
;----------------------------
; put thread back on a queue and get a new one
.next_thread:
mov ecx,esp
call scheduler_enqueue_normal
call scheduler_dequeue_intel
;----------------------------
; check if this is a ring0 thread
mov ecx,[eax+thread_t.esp0]
test ecx,ecx
je .stack_change
;----------------------------
; check if we need to change cr3
mov edx,cr3
mov ebx,[eax+thread_t.pd]
cmp ebx,edx
je .stack_change
mov cr3,ebx
;----------------------------
; set new esp
.stack_change:
mov esp,[eax+thread_t.esp3]
mov [tss_cpu0.esp0],ecx
;----------------------------
align 4
.end:
return_irq1
endp
;----------------------------
;----------------------------
proc scheduler_enqueue_normal
;----------------------------
begin
;----------------------------
; save esp
mov [eax+thread_t.esp3],ecx
;----------------------------
; look if we just ran the idle thread
cmp eax,idle_thread
je .end
;----------------------------
; get and check the flags of the thread
mov ebx,[eax+thread_t.flags]
test ebx,thread_kill
jne .kill
test ebx,thread_wait
jne .wait
test ebx,thread_sleep
jne .sleep
;----------------------------
; enqueue the thread into the ready queue
; test dword[scheduler_flags],scheduler_reschedule
; jne .do_it
; cmp dword[eax+thread_t.dyn_prio],0
; je .do_it
; sub dword[eax+thread_t.dyn_prio],1
;----------------------------
; put it onto the ready queue
.do_it:
mov ecx,[eax+thread_t.dyn_prio]
mov ebx,1
mov esi,[ready_queue_ptr]
shl ebx,cl
or [ready_queue_bitmap],ebx
mov edi,[esi+4*ecx]
test edi,edi
je .first
mov ebx,[edi+thread_t.prev]
mov [edi+thread_t.prev],eax
mov [eax+thread_t.prev],ebx
mov [eax+thread_t.next],edi
mov [ebx+thread_t.next],eax
jmp .end
;----------------------------
; it is the first thread in this priority
align 4
.first:
mov [eax+thread_t.prev],eax
mov [eax+thread_t.next],eax
mov [esi+4*ecx],eax
jmp .end
;----------------------------
; the thread waits for something in a wait queue
align 4
.wait:
; cmp dword[eax+thread_t.dyn_prio],31
; je .test_schd_queue
; add dword[eax+thread_t.dyn_prio],1
jmp .end
;----------------------------
; the owner of the thread is going to be killed
align 4
.kill:
xor ecx,ecx
mov [eax+thread_t.prev],ecx
mov [eax+thread_t.next],ecx
jmp .end
;----------------------------
; the thread wants to sleep
align 4
.sleep:
;to-do
jmp .end
;----------------------------
align 4
.end:
and dword[scheduler_flags],not scheduler_reschedule
return
endp
;----------------------------
;----------------------------
proc scheduler_dequeue_intel
;----------------------------
begin
;----------------------------
; get the thread with the highest priority
; mov eax,[run_queue_bitmap]
mov edx,[run_queue_bitmap]
mov esi,[run_queue_ptr]
;----------------------------
; get the highest priority thread
.get_thread:
; nop
; bsr eax,eax
bsr eax,edx
jz .change_queues
mov ebx,[esi+4*eax]
mov edx,[ebx+thread_t.next]
mov ecx,[ebx+thread_t.prev]
cmp edx,ebx
je .last
mov [esi+4*eax],edx
mov [ecx+thread_t.next],edx
mov [edx+thread_t.prev],ecx
mov eax,ebx
;----------------------------
; move the needed vales from the thread struc in the right regs
.init:
cmp eax,[schdl_act_thread]
je .end
mov [schdl_act_thread],eax
;----------------------------
; set base addr for fs and gs regs
mov word[GDT + 5*gdt_entry_t.size_t + gdt_entry_t.base_addr_0_15],ax
add eax,thread_t.free_start
mov word[GDT + 6*gdt_entry_t.size_t + gdt_entry_t.base_addr_0_15],ax
shr eax,16
mov byte[GDT + 5*gdt_entry_t.size_t + gdt_entry_t.base_addr_16_23],al
mov byte[GDT + 6*gdt_entry_t.size_t + gdt_entry_t.base_addr_16_23],al
shr eax,8
mov byte[GDT + 5*gdt_entry_t.size_t + gdt_entry_t.base_addr_24_31],al
mov byte[GDT + 6*gdt_entry_t.size_t + gdt_entry_t.base_addr_24_31],al
;----------------------------
; write the esp value for the ring0 code into the msr reg
mov eax,[fs:thread_t.esp0]
mov ecx,176h
xor edx,edx
wrmsr
jmp .end
;----------------------------
; this is the last thread in the queue, so del the bit in the bitmap
align 4
.last:
mov edx,ebx
xor ecx,ecx
mov ebx,1
mov [esi+4*eax],ecx
mov ecx,eax
shl ebx,cl
; not ebx
; and [run_queue_bitmap],ebx
xor [run_queue_bitmap],ebx
mov eax,edx
jmp .init
;----------------------------
; we have to change the queues
align 4
.change_queues:
mov eax,[run_queue_bitmap]
mov ebx,[run_queue_ptr]
xchg eax,[ready_queue_bitmap]
xchg ebx,[ready_queue_ptr]
mov [run_queue_bitmap],eax
mov [run_queue_ptr],ebx
mov eax,[run_queue_bitmap]
mov esi,[run_queue_ptr]
test eax,eax
jnz .get_thread
;----------------------------
; there is no thread so we take the idle thread
mov eax,idle_thread
jmp .init
;----------------------------
align 4
.end:
;----------------------------
; we removed the thread from the queue and we need to give the thread some time 2 run
mov eax,[schdl_act_thread]
xor ebx,ebx
mov ecx,32
mov [eax+thread_t.prev],ebx
sub ecx,[eax+thread_t.dyn_prio]
mov [eax+thread_t.next],ebx
mov [eax+thread_t.time2run],ecx
;----------------------------
return
endp
;----------------------------
;----------------------------
proc scheduler_add_scheduler, ptr2thread
;----------------------------
begin
call semaphore_acquire, sem_schdl_queue
cli
;----------------------------
; add thread to ready queue
mov esi,[ptr2thread]
mov ebx,1
mov ecx,[esi+thread_t.dyn_prio]
mov edi,[ready_queue_ptr]
shl ebx,cl
or [ready_queue_bitmap],ebx
mov eax,[edi+4*ecx]
test eax,eax
jz .first
mov ebx,[eax+thread_t.prev]
mov [esi+thread_t.next],eax
mov [esi+thread_t.prev],ebx
mov [eax+thread_t.prev],esi
mov [ebx+thread_t.next],esi
jmp .end
;----------------------------
; it is the 1st thread in this priority queue
align 4
.first:
mov [esi+thread_t.prev],esi
mov [esi+thread_t.next],esi
mov [edi+4*ecx],esi
;----------------------------
align 4
.end:
or dword[scheduler_flags],scheduler_reschedule
sti
call semaphore_release, sem_schdl_queue
return
endp
;----------------------------
My problem is, that if the function "scheduler_dequeue_intel" is like this, it isn´t working in Bochs and Qemu. If I change the code, so that I only use "eax" for the bitmap then the code works (most of the time) in Qemu, but not in Bochs. If I put a "nop" before the "bsr" instruction, then it works in Bochs, but not long in Qemu (it works for 30 seconds or so).
My question now is, why doesn´t the code work like it is now? I only change the register where the bitmap is loaded! And why is it working in Bochs if I place a "nop" before the "bsr" instruction?
|