BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

SpinLock
Goto page 1, 2  Next
 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Language BASM
View previous topic :: View next topic  
Author Message
Lee_Nover
Guest





PostPosted: Sun Mar 25, 2007 6:31 pm    Post subject: SpinLock Reply with quote



hi
I've done my first little ASM project and would like some guides
it's a spinlock object that acquires/releases a lock
the Acquire method with a backoff is not yet implemented in asm

any insight will be much appreciated

tnx!



unit SpinLock;
{
#==============================================================================
# Name: SpinLock.pas
# Author: Istvan Agoston <Lee_Nover@delphi-si.com>
# Created: 2007-03-25
# Last Change: 2007-03-25
# Version: 1.0

# Description:

A scalable atomic lock

http://www.intel.com/cd/ids/developer/asmo-na/eng/dc/threading/333935..htm


# Warnings and/or special considerations:

Source code in this file is subject to the license specified below.

#==============================================================================
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
the specific language governing rights and limitations under the License.

The Original Code is 'SpinLock.pas'.

The Initial Developer of the Original Code is 'Istvan Agoston'.

Contributor(s): None.

#==============================================================================}

{$DEFINE ASM}

interface

type
TSpinLock = class(TObject)
private
FOwner: Cardinal;
FSleepAmount: Cardinal;
public
constructor Create(const SleepAmount: Cardinal = 0);
destructor Destroy; override;
procedure Acquire; overload;
function Acquire(TryCount: Cardinal): Boolean; overload;
procedure Release;
end;

implementation

uses Windows;

{ compares CompareValue and Target and returns the initial value of Target
if they're equal, Target is set to NewVal }
function LockCmpxchg(CompareVal, NewVal: Cardinal; var Target: Cardinal): Cardinal;
asm
lock cmpxchg [ecx], edx
end;

constructor TSpinLock.Create(const SleepAmount: Cardinal = 0);
begin
inherited Create;
FSleepAmount := SleepAmount;
end;

destructor TSpinLock.Destroy;
begin
FOwner := 0;
inherited;
end;

procedure TSpinLock.Acquire;
{$IFNDEF ASM}
var
LOwner: Cardinal;
LLock: Cardinal;
begin
LLock := GetCurrentThreadId;
// if not owned, set ourself as owner
LOwner := LockCmpxchg(0, LLock, FOwner);
// if the lock is owned by some other thread
while (LOwner <> 0) and (LOwner <> LLock) do
begin
Sleep(FSleepAmount);
LOwner := LockCmpxchg(0, LLock, FOwner);
end;
{$ELSE}
asm
// store Self in edx
mov edx, eax
// get thread id
mov ecx, fs:[$00000018]
mov ecx,[ecx+$24]
// clear eax for comparison to 0
xor eax, eax
// if owner equals 0 then safely exchange it with our thread id
lock cmpxchg [edx].FOwner, ecx
// if previously not owned then exit
jz @@exit
cmp eax, ecx
// if the owner is our threadid then exit (recursive locks)
jz @@exit

@@waitloop:
// spin on a volatile read
cmp [edx].FOwner, 0
jz @@trylock
// save our registers because sleep modifies them
push edx
push ecx
// Sleep is stdcall and accepts params on the stack, we push FSleepAmount as timeout
push FSleepAmount
call Windows.Sleep
pop ecx
pop edx
jmp @@waitloop

@@trylock:
xor eax, eax
// lock
lock cmpxchg [edx].FOwner, ecx
// if lock not successfull then reenter the loop
jnz @@waitloop

@@exit:
nop
{$ENDIF}
end;

function TSpinLock.Acquire(TryCount: Cardinal): Boolean;
var
LOwner: Cardinal;
LLock: Cardinal;
begin
LLock := GetCurrentThreadId;
// if not owned, set ourself as owner
LOwner := LockCmpxchg(0, LLock, FOwner);
// if the lock is owned by some other thread
while (LOwner <> 0) and (LOwner <> LLock) and (TryCount > 0) do
begin
Dec(TryCount);
Sleep(FSleepAmount);
LOwner := LockCmpxchg(0, LLock, FOwner);
end;

Result := TryCount > 0;
end;

procedure TSpinLock.Release;
{$IFNDEF ASM}
var
LLock: Cardinal;
begin
LLock := GetCurrentThreadId;
LockCmpxchg(LLock, 0, FOwner);
{$ELSE}
asm
// store self in edx
mov edx, eax
// get thread id
mov eax, fs:[$00000018]
mov eax,[eax+$24]
// clear ecx for reseting the lock if ecx equals owner
xor ecx, ecx
// if owner equals our thread id then safely exchange owner with 0
lock cmpxchg [edx].FOwner, ecx
{$ENDIF}
end;

end.
Back to top
Lee_Nover
Guest





PostPosted: Sun Mar 25, 2007 8:29 pm    Post subject: Re: SpinLock Reply with quote



Quote:
I've done my first little ASM project and would like some guides
it's a spinlock object that acquires/releases a lock
the current implementation is available from here:

http://leenover.homeip.net/isapi/pas2html.dll/pas2html?File=/delphi/MiscStuff/SpinLock

Quote:
the Acquire method with a backoff is not yet implemented in asm
this has been implemented
Back to top
Robert Marquardt
Guest





PostPosted: Mon Mar 26, 2007 2:19 pm    Post subject: Re: SpinLock Reply with quote



Lee_Nover wrote:
Quote:
hi
I've done my first little ASM project and would like some guides
it's a spinlock object that acquires/releases a lock

Would you donate it to the JCL?
Back to top
Henri Gourvest
Guest





PostPosted: Mon Mar 26, 2007 4:46 pm    Post subject: Re: SpinLock Reply with quote

many thanks :)

Lee_Nover a écrit :
Quote:
hi
I've done my first little ASM project and would like some guides
it's a spinlock object that acquires/releases a lock
the Acquire method with a backoff is not yet implemented in asm

any insight will be much appreciated

tnx!



unit SpinLock;
{
#===============================================================================

# Name: SpinLock.pas
# Author: Istvan Agoston <Lee_Nover@delphi-si.com
# Created: 2007-03-25
# Last Change: 2007-03-25
# Version: 1.0

# Description:

A scalable atomic lock

http://www.intel.com/cd/ids/developer/asmo-na/eng/dc/threading/333935.htm


# Warnings and/or special considerations:

Source code in this file is subject to the license specified below.

#===============================================================================

The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
the specific language governing rights and limitations under the License.

The Original Code is 'SpinLock.pas'.

The Initial Developer of the Original Code is 'Istvan Agoston'.

Contributor(s): None.

#===============================================================================
}

{$DEFINE ASM}

interface

type
TSpinLock = class(TObject)
private
FOwner: Cardinal;
FSleepAmount: Cardinal;
public
constructor Create(const SleepAmount: Cardinal = 0);
destructor Destroy; override;
procedure Acquire; overload;
function Acquire(TryCount: Cardinal): Boolean; overload;
procedure Release;
end;

implementation

uses Windows;

{ compares CompareValue and Target and returns the initial value of Target
if they're equal, Target is set to NewVal }
function LockCmpxchg(CompareVal, NewVal: Cardinal; var Target: Cardinal): Cardinal;
asm
lock cmpxchg [ecx], edx
end;

constructor TSpinLock.Create(const SleepAmount: Cardinal = 0);
begin
inherited Create;
FSleepAmount := SleepAmount;
end;

destructor TSpinLock.Destroy;
begin
FOwner := 0;
inherited;
end;

procedure TSpinLock.Acquire;
{$IFNDEF ASM}
var
LOwner: Cardinal;
LLock: Cardinal;
begin
LLock := GetCurrentThreadId;
// if not owned, set ourself as owner
LOwner := LockCmpxchg(0, LLock, FOwner);
// if the lock is owned by some other thread
while (LOwner <> 0) and (LOwner <> LLock) do
begin
Sleep(FSleepAmount);
LOwner := LockCmpxchg(0, LLock, FOwner);
end;
{$ELSE}
asm
// store Self in edx
mov edx, eax
// get thread id
mov ecx, fs:[$00000018]
mov ecx,[ecx+$24]
// clear eax for comparison to 0
xor eax, eax
// if owner equals 0 then safely exchange it with our thread id
lock cmpxchg [edx].FOwner, ecx
// if previously not owned then exit
jz @@exit
cmp eax, ecx
// if the owner is our threadid then exit (recursive locks)
jz @@exit

@@waitloop:
// spin on a volatile read
cmp [edx].FOwner, 0
jz @@trylock
// save our registers because sleep modifies them
push edx
push ecx
// Sleep is stdcall and accepts params on the stack, we push FSleepAmount as timeout
push FSleepAmount
call Windows.Sleep
pop ecx
pop edx
jmp @@waitloop

@@trylock:
xor eax, eax
// lock
lock cmpxchg [edx].FOwner, ecx
// if lock not successfull then reenter the loop
jnz @@waitloop

@@exit:
nop
{$ENDIF}
end;

function TSpinLock.Acquire(TryCount: Cardinal): Boolean;
var
LOwner: Cardinal;
LLock: Cardinal;
begin
LLock := GetCurrentThreadId;
// if not owned, set ourself as owner
LOwner := LockCmpxchg(0, LLock, FOwner);
// if the lock is owned by some other thread
while (LOwner <> 0) and (LOwner <> LLock) and (TryCount > 0) do
begin
Dec(TryCount);
Sleep(FSleepAmount);
LOwner := LockCmpxchg(0, LLock, FOwner);
end;

Result := TryCount > 0;
end;

procedure TSpinLock.Release;
{$IFNDEF ASM}
var
LLock: Cardinal;
begin
LLock := GetCurrentThreadId;
LockCmpxchg(LLock, 0, FOwner);
{$ELSE}
asm
// store self in edx
mov edx, eax
// get thread id
mov eax, fs:[$00000018]
mov eax,[eax+$24]
// clear ecx for reseting the lock if ecx equals owner
xor ecx, ecx
// if owner equals our thread id then safely exchange owner with 0
lock cmpxchg [edx].FOwner, ecx
{$ENDIF}
end;

end.
Back to top
John Herbster
Guest





PostPosted: Mon Mar 26, 2007 5:18 pm    Post subject: Re: SpinLock Reply with quote

"Henri Gourvest" <x (AT) x (DOT) com> wrote
Quote:
many thanks Smile
....

Did a little overquoting occur in that reply or did I
miss more of the reply than the two words above?
--JohnH
Back to top
Lee_Nover
Guest





PostPosted: Mon Mar 26, 2007 6:13 pm    Post subject: Re: SpinLock Reply with quote

Quote:
it's a spinlock object that acquires/releases a lock

I've made a shared memory descendant of the lock
it can work between processes (also created by different users)

the SharedSpinLock needs a little work under the hood:
instead of allocating pages for every spinlock, I'll create one map to hold multiple locks
should be ready later today
on the outside there won't be any difference (api will stay the same)
Back to top
Robert Marquardt
Guest





PostPosted: Mon Mar 26, 2007 7:21 pm    Post subject: Re: SpinLock Reply with quote

Lee_Nover wrote:

Quote:
I've made a shared memory descendant of the lock
it can work between processes (also created by different users)

FYI i have heard about problems with shared memory on Vista. It seems
that if a service is involved not all can open the map.
If i recall correctly the service cannot see the map if created by a
normal application.
Back to top
Lee_Nover
Guest





PostPosted: Mon Mar 26, 2007 7:33 pm    Post subject: Re: SpinLock Reply with quote

Quote:
I've made a shared memory descendant of the lock
it can work between processes (also created by different users)

FYI i have heard about problems with shared memory on Vista. It seems
that if a service is involved not all can open the map.
If i recall correctly the service cannot see the map if created by a
normal application.

even with correct security descriptors?
I'll try it out and report later
Back to top
Lee_Nover
Guest





PostPosted: Mon Mar 26, 2007 9:33 pm    Post subject: Re: SpinLock Reply with quote

Quote:
FYI i have heard about problems with shared memory on Vista. It seems
that if a service is involved not all can open the map.
If i recall correctly the service cannot see the map if created by a
normal application.

even with correct security descriptors?
I'll try it out and report later

seems to work just fine

but while the service runs like this, the user app waits and waits for its turn Smile
if I pause (/w breakpoint) the service right after FLock.Release, then the user app finishes fine
this works regardless of who created the lock

procedure TsvcSpinLockTest.ServiceExecute(Sender: TService);
begin
FLock := TSharedSpinLock.Create('TestSharedSpinLock', 0);
try
while not Terminated do
begin
Sender.ServiceThread.ProcessRequests(False);
FLock.Acquire;
try
Sleep(1);
finally
FLock.Release;
end;
end;
finally
FLock.Free;
end;
end;
Back to top
Lee_Nover
Guest





PostPosted: Mon Mar 26, 2007 11:28 pm    Post subject: Re: SpinLock Reply with quote

Quote:
I've done my first little ASM project and would like some guides
it's a spinlock object that acquires/releases a lock

Would you donate it to the JCL?

sure Smile can't see why not

just updated the sources
Back to top
Davy Landman
Guest





PostPosted: Tue Mar 27, 2007 1:12 am    Post subject: Re: SpinLock Reply with quote

Hi,

I just wanted to say thanks for the nice code!

allready using it in a project of mine..

:)

Quote:
the SharedSpinLock needs a little work under the hood:
instead of allocating pages for every spinlock, I'll create one map to
hold multiple locks
should be ready later today
on the outside there won't be any difference (api will stay the same)

I was wondering how you're going to do the lookup of the correct "lock
handle"? (by How I mean which algorithm?)
If it's some kind of data structure algorithm, it would need to be lock free
too, or else I would think the advantage of the spin locks are lost?

I don't think using the memory maps methode is that bad, Windows uses alot
internally, therefor it should be farely optimised :)

But anyhow, interesting code on your site!

Kind regards,
Davy Landman
Back to top
Lee_Nover
Guest





PostPosted: Tue Mar 27, 2007 2:18 am    Post subject: Re: SpinLock Reply with quote

Quote:
I just wanted to say thanks for the nice code!
tnx


Quote:
on the outside there won't be any difference (api will stay the same)
I was wondering how you're going to do the lookup of the correct "lock
handle"? (by How I mean which algorithm?)


ah, didn't want to loose to much time with that so I went with a simple Index
the Index is app specific, plus there are lock Groups based on name

so you can have:
const
LockIndexDBConnPool = 0;
LockIndexGlobalObject = 1;
and
TSharedSpinLock.Create('company-app-section', LockIndexDBConnPool, 10);
TSharedSpinLock.Create('company-app-section', LockIndexGlobalObject, 10);
the Group parameter specifies the name of the memory mapped file and can further separate the locks
this way the memory page is also protected from other applications


Quote:
If it's some kind of data structure algorithm, it would need to be lock free
too, or else I would think the advantage of the spin locks are lost?
I already implemented that using a hash algorightm, but didn't find a reliable one

so I simply changed Name to Index .. both are app specific and there's _no difference_ in declaring a string const or an integer const :)


Quote:
But anyhow, interesting code on your site!
hope you find something useful

go crazy Smile
Back to top
Primoz Gabrijelcic
Guest





PostPosted: Tue Mar 27, 2007 11:59 pm    Post subject: SpinLock test/bench suite Reply with quote

Lee_Nover wrote:

Quote:
I've done my first little ASM project and would like some guides
it's a spinlock object that acquires/releases a lock
the Acquire method with a backoff is not yet implemented in asm

I have put together a simple test/benchmark suite:
http://www.gabrijelcic.org/testSpinLock.zip.

--
Primoz
Back to top
Freddy
Guest





PostPosted: Wed Mar 28, 2007 12:18 am    Post subject: Re: SpinLock test/bench suite Reply with quote

In short, when would I use a spinlock instead of a critical section?
Or should I simply replace each critical-section with a spinlock?

My target is multi-processor (2 min), video cache access by multiple clients
etc..

Any guidance?

Thanks,
Freddy

"Primoz Gabrijelcic" <primoz (AT) gabrijelcic (DOT) org> wrote in message
news:46095b75 (AT) newsgroups (DOT) borland.com...
Quote:
Lee_Nover wrote:

I've done my first little ASM project and would like some guides
it's a spinlock object that acquires/releases a lock
the Acquire method with a backoff is not yet implemented in asm

I have put together a simple test/benchmark suite:
http://www.gabrijelcic.org/testSpinLock.zip.

--
Primoz
Back to top
Lee_Nover
Guest





PostPosted: Wed Mar 28, 2007 1:26 am    Post subject: Re: SpinLock test/bench suite Reply with quote

Quote:
In short, when would I use a spinlock instead of a critical section?
Or should I simply replace each critical-section with a spinlock?

My target is multi-processor (2 min), video cache access by multiple clients
etc..

Any guidance?

use it if:
have multiple cpus
don't care the order the threads get the lock
have a lot of threads acquiring the same resource (>10)

anyway I wouldn't go crazy-change existing code .. but I am using it in new projects
Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Language BASM All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.