flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Semaphore function on smp

Author
Thread Post new topic Reply to topic
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn
I have a problem with my semaphore function on a smp system! On an uni-cpu systems all is working ok, but on a smp system the last thread on the semaphore´s queue is waked up when the counter is -2!?

Here is the code:
Code:
;----------------------------
PROC semaphore_acquire_normal, sem
;----------------------------
BEGIN
;----------------------------
;       make sure we are the only one to work on the semaphore
        cli

        CALL mutex_acquire, dword[sem]

        lock sub dword[esi+semaphore_t.count],1
        jz .end
;----------------------------
;       look if we have to wait or we can go right away
        cmp dword[esi+semaphore_t.count],0
        jg .end
;----------------------------
;       we have to wait
        mov edi,[esi+semaphore_t.threads]
        mov eax,[cpu0.schdl_act_thread]

        test edi,edi
        jz .first

        mov ebx,[edi+thread_t.prev]
        xor ecx,ecx
        mov [eax+thread_t.prev],ebx
        mov [eax+thread_t.next],ecx
        mov [edi+thread_t.prev],eax
        mov [ebx+thread_t.next],eax

        jmp .scheduler
;----------------------------
;       we are the first thread
align 4
.first:
        mov [esi+semaphore_t.threads],eax

        mov [eax+thread_t.prev],eax
        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[schdl_flags],SCHEDULER_RESCHEDULE

        CALL mutex_release, dword[sem]

        sti

        CALLINT scheduler_reschedule_normal

.end_wait:
        RETURN
;----------------------------
align 4
.end:
        CALL mutex_release, dword[sem]

        sti

        RETURN
ENDP
;----------------------------

;----------------------------
PROC semaphore_acquire_smp, sem
;----------------------------
BEGIN
;----------------------------
;       make sure we are the only one to work on the semaphore
        cli

        CALL mutex_acquire, dword[sem]

        lock sub dword[esi+semaphore_t.count],1
        jz .end
;----------------------------
;       look if we have to wait or we can go right away
        cmp dword[esi+semaphore_t.count],0
        jg .end
;----------------------------
;       we have to wait
        APIC_GET_ID eax
        mov ebx,[cpu_ptr+4*eax]
        mov edi,[esi+semaphore_t.threads]
        mov eax,[ebx+cpu_t.schdl_act_thread]

        test edi,edi
        jz .first

        mov ebx,[edi+thread_t.prev]
        xor ecx,ecx
        mov [eax+thread_t.prev],ebx
        mov [eax+thread_t.next],ecx
        mov [edi+thread_t.prev],eax
        mov [ebx+thread_t.next],eax

        jmp .scheduler
;----------------------------
;       we are the first thread
align 4
.first:
        mov [esi+semaphore_t.threads],eax

        mov [eax+thread_t.prev],eax
        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[schdl_flags],SCHEDULER_RESCHEDULE

        CALL mutex_release, dword[sem]

        sti

        CALLINT scheduler_reschedule_smp

.end_wait:
        RETURN
;----------------------------
align 4
.end:
        CALL mutex_release, dword[sem]

        sti

        RETURN
ENDP
;----------------------------

;----------------------------
PROC semaphore_release, sem
;----------------------------
BEGIN
;----------------------------
;       make sure we are the only one to work on the semaphore
        cli

        CALL mutex_acquire, dword[sem]

        lock add dword[esi+semaphore_t.count],1
;----------------------------
;       look if we need to awake a thread
        cmp dword[esi+semaphore_t.count],0
        jg .end
;----------------------------
;       we have to awake the thread on the top of the queue
        mov eax,[esi+semaphore_t.threads]

        test eax,eax
        jnz .go_on

        mov eax,[esi+semaphore_t.count]

        int 0

align 4
.go_on:
        mov ebx,[eax+thread_t.next]
        mov ecx,[eax+thread_t.prev]

        test ebx,ebx
        jz .last

        mov [ecx+thread_t.prev],ebx
        mov [esi+semaphore_t.threads],ecx

        jmp .scheduler
;----------------------------
;       there is no more thread on the queue
align 4
.last:
        cmp dword[esi+semaphore_t.count],0
        je .last@go_on

        mov eax,[esi+semaphore_t.count]

        int 0

align 4
.last@go_on:
        mov [esi+semaphore_t.threads],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]

        sti

        CALL scheduler_add_scheduler                    ;par is in pushed eax
;----------------------------
.end_awaken:
        RETURN
;----------------------------
align 4
.end:
        CALL mutex_release, dword[sem]

        sti

        RETURN
ENDP
;----------------------------
    


If you need more info then ask!
Post 07 Aug 2005, 21:01
View user's profile Send private message Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn
Anyone here who could help me?
Post 08 Aug 2005, 16:47
View user's profile Send private message Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 559
smiddy
Sorry man, I wish I could. I'm currently swamped with making a device manager, not focusing on SMP (or HT) yet, until I've nailed down my device manager. Brendan on Mega-Tokyo may be able to help. The site: http://www.mega-tokyo.com/forum/

He has working out some coding for SMP as I recall.
Post 08 Aug 2005, 19:47
View user's profile Send private message Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn
I´ve posted my question there too, but also there was anyone you could help me Sad So I have to solve this problem by myself. Although I´m working on this for weeks now.
Post 09 Aug 2005, 13:05
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
You have aligned all data related to synchronization mechanisms? I don't know if that is the problem but when you want an operation to be atomic you need the data aligned
Post 09 Aug 2005, 13:29
View user's profile Send private message Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn
The data is align to 4bytes at minimum.

I tested my code with 4 threads on an uni-cpu system! And I thought I can´t believe my eyes - it wasn´t working Shocked - The thing is that I only tested it with 3 threads on a uni cpu system and with 2 threads per cpu on a dual system. So something has to be wrong with my algorithm! Maybe you could have a look at it.

The problem is that when I have 4 threads which are using one semaphore and then all 4 threads are run and the 4th gives up the count is -2 after it decreased the counter and there is no thread in the queue.

I use the semaphore for my putchar function and the output looks like this (the number is the thread number):
Code:
111111111111111111111111222222222222222222222222222233333333333333333334
    


Then int 0 is called to show me that something went wrong!

I hope that you can help me now!
Post 09 Aug 2005, 13:55
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Again not sure but, did you have noted when you jump to scheduler then you return without trying to acquire the semaphore again?

Also I don't know why you use CLI (I'm not saying it's wrong). Also check (esi+semaphore_t.count) mod 4 == 0 because you will have problems with "lock sub dword[esi+semaphore_t.count],1".

I hope this helps

PS: If you will try to repeat the acquire remember to do an "lock add dword[esi+semaphore_t.count],1" before.

[edit]Ups sorry, what is exactly your problem? Do you have threads running with a counter < 0 or you multiple threads running?
Apparently the output you show me with putchar says that only one thread is executing[/edit]
Post 09 Aug 2005, 15:00
View user's profile Send private message Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn
I do not need to acquire the semaphore again, because when the thread that has the semaphore releases it then it also looks are there threads who are waiting and awakens the thread from the top of the queue and this thread then has the semaphore!

Edit::

The Problem is this:
Code:
threads wants to release the semaphore
threads gets mutex
counter=-3
-> add counter,1 
counter=-2
problem there are no threads on the queue????
    
Post 09 Aug 2005, 15:25
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
With the description of the problem it's appear to be a problem with the queues but since the putchar works I don't think the queues are wrong.

Sorry I can't see the problem :'(
Post 09 Aug 2005, 16:17
View user's profile Send private message Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn
It is a problem with the queues, but I´ve rewritten the code 2 times and so I don´t see a problem! Also the problem only appears with 4 and more threads!
Post 09 Aug 2005, 17:38
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Take a look to this and tell me if my analysis is correct
Code:
5)Now the first thread releases the semaphore
;       we have to awake the thread on the top of the queue 
        mov eax,[esi+semaphore_t.threads] ; eax = firstNode(prev=>forthNode, next=>secondNode)


        test eax,eax 
        jnz .go_on 

        mov eax,[esi+semaphore_t.count] 

        int 0 

align 4 
.go_on: 
        mov ebx,[eax+thread_t.next]       ; ebx = secondNode
        mov ecx,[eax+thread_t.prev]       ; ecx = forthNode

        test ebx,ebx 
        jz .last                          ; it's not the last

        mov [ecx+thread_t.prev],ebx       ; forthNode.prev = secondNode
        mov [esi+semaphore_t.threads],ecx ; Top of queue = forthNode(prev=>secondNode,next=>NULL)<<<--- WHAT???!!!


4)forth thread entering in the queue

        mov edi,[esi+semaphore_t.threads] ; edi = firstNode(prev=>thirthNode, next=>secondNode)
        mov eax,[cpu0.schdl_act_thread]   ; eax = forthNode(prev=>NULL, next=>NULL)

        test edi,edi 
        jz .first                         ; It's the 4th this time

        mov ebx,[edi+thread_t.prev]       ; ebx = firstNode.prev = thirthNode
        xor ecx,ecx 
        mov [eax+thread_t.prev],ebx       ; forthNode.prev = thirthNode
        mov [eax+thread_t.next],ecx       ; forthNode.next = NULL
        mov [edi+thread_t.prev],eax       ; firstNode.prev = forthNode
        mov [ebx+thread_t.next],eax       ; thirthNode.next = forthNode

3)thirth thread entering in the queue

        mov edi,[esi+semaphore_t.threads] ; edi = firstNode(prev=>secondNode, next=>secondNode)
        mov eax,[cpu0.schdl_act_thread]   ; eax = thirthNode(prev=>NULL, next=>NULL)

        test edi,edi 
        jz .first                         ; It's the 3th this time

        mov ebx,[edi+thread_t.prev]       ; ebx = firstNode.prev = secondNode
        xor ecx,ecx 
        mov [eax+thread_t.prev],ebx       ; thirthNode.prev = secondNode
        mov [eax+thread_t.next],ecx       ; thirthNode.next = NULL
        mov [edi+thread_t.prev],eax       ; firstNode.prev = thirthNode
        mov [ebx+thread_t.next],eax       ; secondNode.next = thirthNode

2)second thread entering on the queue

        mov edi,[esi+semaphore_t.threads] ; edi = firstNode(prev=>firstNode, next=>NULL)
        mov eax,[cpu0.schdl_act_thread]   ; eax = secondNode(prev=>NULL, next=>NULL)

        test edi,edi 
        jz .first                         ; It's the 2nd this time

        mov ebx,[edi+thread_t.prev]       ; ebx = firstNode.prev = firstNode
        xor ecx,ecx 
        mov [eax+thread_t.prev],ebx       ; secondNode.prev = firstNode
        mov [eax+thread_t.next],ecx       ; secondNode.next = NULL
        mov [edi+thread_t.prev],eax       ; firstNode.prev = secondNode
        mov [ebx+thread_t.next],eax       ; firstNode.next = secondNode


1)first time

.first: 
        mov [esi+semaphore_t.threads],eax ; eax = firstNode(prev=>NULL, next=>NULL)

        mov [eax+thread_t.prev],eax       ; firstNode.prev = firstNode
        mov [eax+thread_t.next],edi       ; fistNode.next = NULL    
Post 09 Aug 2005, 21:14
View user's profile Send private message Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn
Thanks, you opend my eyes! As I read your comments I saw something that couldn´t be.

Here is the correct release function:
Code:
;-- --------------------------
PROC semaphore_release, sem
;----------------------------
BEGIN
;----------------------------
;       make sure we are the only one to work on the semaphore
        cli

        CALL mutex_acquire, dword[sem]

        lock add dword[esi+semaphore_t.count],1
;----------------------------
;       look if we need to awake a thread
        cmp dword[esi+semaphore_t.count],0
        jg .end
;----------------------------
;       we have to awake the thread on the top of the queue
        mov eax,[esi+semaphore_t.threads]
        mov ebx,[eax+thread_t.next]
        mov ecx,[eax+thread_t.prev]

        test ebx,ebx
        jz .last

;       mov [ecx+thread_t.prev],ebx              <- why putting the 2nd thread into the last thread as previous
;       mov [esi+semaphore_t.threads],ecx    <- why putting the last thread onto the head of the queue
        mov [ebx+thread_t.prev],ecx
        mov [esi+semaphore_t.threads],ebx

        jmp .scheduler
;----------------------------
;       there is no more thread on the queue
align 4
.last:
        mov [esi+semaphore_t.threads],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]

        sti

        CALL scheduler_add_scheduler                    ;par is in pushed eax
;----------------------------
.end_awaken:
        RETURN
;----------------------------
align 4
.end:
        CALL mutex_release, dword[sem]

        sti

        RETURN
ENDP
;----------------------------
    


Maybe this code is usefull for others, too!
Post 09 Aug 2005, 21:58
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-2020, Tomasz Grysztar.

Powered by rwasa.