flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Semaphore and scheduler

Author
Thread Post new topic Reply to topic
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn 07 Jun 2005, 08:14
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:
Code:
;----------------------------
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:
Code:
;----------------------------
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:

Code:
;----------------------------
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?
Post 07 Jun 2005, 08:14
View user's profile Send private message Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn 07 Jun 2005, 18:51
OK, I found my fault! I´m searching and searching (for over 3 month now) at the wrong code! I thought it was a problem with my semaphores, but it was a problem of the scheduler. I sub 1 from the time2run field in the thread struc, but where to I go when the time isn´t over I put it back into the queue. I don´t know why this makes all of the code don´t work, but now I changed this line and the code works in Bochs, in Qemu and on my PC!
Post 07 Jun 2005, 18:51
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.