[comp.sys.amiga.tech] Semaphores

TLIMONCE@DREW.BITNET (05/27/88)

I have a question about Semaphores.

I have used Semaphores on other systems but I can't figure out how to do
them on the Amiga.  I'm sure this would be of public interest so if
someone could just post a quick summery of how to allocated them, UP() and
DOWN() them, and destroy them.  (or anything else I should know).

I have the 1.2 Autodocs... but I must not have my eyes on straight when I
read them because I can't figure it out.  Someone told me they are
implemented "like messages".  Well, I have programs talking to other
programs with no problem using regular message ports, etc.

Thanks in advance!

Tom

A     //            Tom Limoncelli -- TLimonce@Drew.Bitnet              \
M    //   "Never trust a person that doesn't know machine language!"     \
I \\//                                                                   /\
G  XX                "Have you hugged your SO today?"                   /  \
A --------------------------------------------------------------------------
  "The above are my views, not those of Drew University or my employer"

carolyn@cbmvax.UUCP (Carolyn Scheppner CATS) (06/08/88)

In article <8805271342.AA13064@jade.berkeley.edu> TLIMONCE@DREW.BITNET writes:
>I have a question about Semaphores.
>...

Check comp.sources.amiga for Phil Lindsay's Semaphore.c.
If it's not there, mail me and I will send it to the sources group.

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CATS   >>Commodore Amiga Technical Support<<
                     UUCP  ...{allegra,ihnp4,rutgers}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

d5adria@dtek.chalmers.se. (Martin Adrian) (11/20/89)

I can't get the function AddSemaphore to work.

My program looks like this:

main()
{
  struct SignalSemaphore ss;

  /* set name and pri */

  AddSemaphore(&ss);

  ....

  RemSemaphore(&ss);
}

The guru will show up every time with different nubers.

When i disassembled the exec function AddSemaphore it looked like this(Ks1.3):
AddSemaphore:  JSR   _LVOInitSemaphore(A6)
	       LEA   SemaphoreList+LH_Head(A6),A0
	       BRA   xxxx    ;do Enqueue

When i looked up the functions in programmers guide i found that AddSemaphore
wants the Semaphorepointer in A1 and InitSemaphore in A0.
(The lattice proto/exec.h was wrong about this)

InitSemaphore also destroys A0,A1,D0,D1.

As far as i can see there is no way that this function can work.
 
 BTW this macro works fine.
#define AddSemaphore(ss) InitSemaphore(ss),\
		         Enqueue(ExecBase->SemaphoreList,&(ss)->ss_Link)
                                                                 ^ 
						   the semaphore node 
Is this a known bug in Exec ?

Martin Adrian.

haeb@ibmpcug.co.uk (Harry Broomhall) (11/25/89)

In article <1716@mathrt0.math.chalmers.se> d5adria@dtek.chalmers.se (Martin Adrian) writes:
> I can't get the function AddSemaphore to work.
> 
> My program looks like this:
> 
  (stuff deleted, but basicaly a simple call to AddSemaphore)
> 
> When i looked up the functions in programmers guide i found that AddSemaphore
> wants the Semaphorepointer in A1 and InitSemaphore in A0.
> (The lattice proto/exec.h was wrong about this)
> 
> Is this a known bug in Exec ?
> 
> Martin Adrian.

  yes - this is documented in the latest edition of RKM, and a work-around
is given:
  void  AddSemaphore(s)
  struct SignalSemaphore *s;
  {
     InitSemaphore(s);
     Forbid();
     Enqueue(&SysBase->SemaphoreList, s);
     Permit();
  }

   Note the use of the Forbid(), Permit() pair when playing with system
lists!

   On another note, Lattice C V5.02 has further faults in proto/exec.h
  The 'magic' numbers given for RemSemaphore and FindSemaphore are
wrong.  They imply that the semaphore is passed in A0, whem in fact it
is in A1.  Alter the numbers from 801 to 901 and all should work.

   Regards,
      Harry Broomhall.


-- 
Automatic Disclaimer:
The views expressed above are those of the author alone and may not
represent the views of the IBM PC User Group.

mks@cbmvax.UUCP (Michael Sinz - CATS) (12/02/89)

In article <1716@mathrt0.math.chalmers.se> d5adria@dtek.chalmers.se (Martin Adrian) writes:
>I can't get the function AddSemaphore to work.
>
>My program looks like this:
>
>main()
>{
>  struct SignalSemaphore ss;
>
>  /* set name and pri */
>
>  AddSemaphore(&ss);

Note that AddSemaphore is Broken in the 1.2/1.3 ROMs and you must use the
work-around published in AmigaMail and in the AutoDocs and in the
RKM: Includes & AutoDocs...  (Blue cover...)

>
>  ....
>
>  RemSemaphore(&ss);
>}
>
>The guru will show up every time with different nubers.
>
>When i disassembled the exec function AddSemaphore it looked like this(Ks1.3):
>AddSemaphore:  JSR   _LVOInitSemaphore(A6)
>	       LEA   SemaphoreList+LH_Head(A6),A0
>	       BRA   xxxx    ;do Enqueue
>
>When i looked up the functions in programmers guide i found that AddSemaphore
>wants the Semaphorepointer in A1 and InitSemaphore in A0.
>(The lattice proto/exec.h was wrong about this)
>
>InitSemaphore also destroys A0,A1,D0,D1.
>
>As far as i can see there is no way that this function can work.
> 
> BTW this macro works fine.
>#define AddSemaphore(ss) InitSemaphore(ss),\
>		         Enqueue(ExecBase->SemaphoreList,&(ss)->ss_Link)
>                                                                 ^ 
>						   the semaphore node 

Note that you need to do the following:

        InitSemaphore(ss);
        Forbid();
        Enqueue(ExecBase->SemaphoreList,ss);
        Permit();

You MUST Forbid()/Permit()

>Is this a known bug in Exec ?
>
>Martin Adrian.



/----------------------------------------------------------------------\
|      /// Michael Sinz -- CATS/Amiga Software Engineer                |
|     ///  PHONE 215-431-9422  UUCP ( uunet | rutgers ) !cbmvax!mks    |
|    ///                                                               |
|\\\///          When people are free to do as they please,            |
| \XX/                they usually imitate each other.                 |
\----------------------------------------------------------------------/

caw@miroc.UUCP (Christopher A. Wichura) (02/03/90)

I am about to start fooling with semaphores for a program I am working on
and have run across something that bothers me.  There is no opposite to
InitSemaphore() that I can find.  When my program wants to exit, which
includes closing down the semaphore, what do I do?  Is it `safe' to simply
drop the semaphore if all ObtainSemaphore()s have been matched by an equal
number of ReleaseSemaphore()s?  This will be a private semaphore so I don't
have to worry about removing it from the system lists, or at least so it
would seem.

-=> CAW
--

/////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
                          Christopher A. Wichura

               ...!jolnet!miroc!caw     (my amiga)         
               u12401@uicvm.uic.edu     (my school account)
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//////////////////////////////////////

mks@cbmvax.commodore.com (Michael Sinz - CATS) (02/12/90)

In article <00253.AA00253@miroc> caw@miroc.UUCP (Christopher A. Wichura) writes:
>I am about to start fooling with semaphores for a program I am working on
>and have run across something that bothers me.  There is no opposite to
>InitSemaphore() that I can find.  When my program wants to exit, which
>includes closing down the semaphore, what do I do?  Is it `safe' to simply
>drop the semaphore if all ObtainSemaphore()s have been matched by an equal
>number of ReleaseSemaphore()s?  This will be a private semaphore so I don't
>have to worry about removing it from the system lists, or at least so it
>would seem.

If the Semaphore is truly PRIVATE then when all users of the semaphore
quit, the semaphore memory can just be FreeMem()ed.  The semaphore contains
only pointers to waiting tasks.  If the semaphore was public, other work
would need to be done.  (Note that this is for SignalSemaphores...)

>
>-=> CAW
>--
>--

/----------------------------------------------------------------------\
|      /// Michael Sinz -- CATS/Amiga Software Engineer                |
|     ///  PHONE 215-431-9422  UUCP ( uunet | rutgers ) !cbmvax!mks    |
|    ///                                                               |
|\\\///          "I don't think so," said Ren'e Descartes.             |
| \XX/                    Just then, he vanished.                      |
\----------------------------------------------------------------------/

ccplumb@lion.waterloo.edu (Colin Plumb) (02/13/90)

In article <00253.AA00253@miroc> caw@miroc.UUCP (Christopher A. Wichura) writes:
> I am about to start fooling with semaphores for a program I am working on
> and have run across something that bothers me.  There is no opposite to
> InitSemaphore() that I can find.  When my program wants to exit, which
> includes closing down the semaphore, what do I do?  Is it `safe' to simply
> drop the semaphore if all ObtainSemaphore()s have been matched by an equal
> number of ReleaseSemaphore()s?  This will be a private semaphore so I don't
> have to worry about removing it from the system lists, or at least so it
> would seem.

It is safe.  A semaphore is just a private data structure manipulated by
Exec which you have to allocate.  Exec only manipulates it on an explicit
call from you, so as long as no processes are dangling off it (which would
result in unrecoverable resources, as the processes would never run and
exit), if you can guarantee that nobody will ever again pass the semaphore
to one of the Exec routines (which is true in your case), you can deallocate
it like any other piece of memory.  InitSemaphore() just sets up the data
structure to the right value; there is no corresponding need to clear
memory before deallocating it.
-- 
	-Colin

arc@desire.wright.edu (06/30/90)

 
 
 
 There is a utility called Stat in the v2.0 of the Kramden utilities.
It has a way to let you list all the semaphores in your system.  There
are only 2 programs that I've seen that use there own semaphore and these
are Tracksalve and some other program (I forget it;s's name).  How come
more people don't use semaphrores?  Wouldn't they help out a lot in some
areas?  I know that semaphorses in a Vax is useful for synchronizing tasks...
Is this what they are used for on the Amiga? Would someone PLEASE elaborate?
 
 /Bryan
 
 
------------------------------------------------------------------------
=     //           | Bryan K. Fite             | Arc@Desire.Wright.edu =
=    // Amiga!     | ^Service Engineer^        |         -or-          =
= \\// The One     | Arc Electronics, Inc.     |    Arc@WSU.BITNET     =
=  \/ & Only...    | Wright State University   |                       =
=                  | Dayton, Ohio              |  Depeche' Mode, Now!  =
========================================================================

Sullivan@cup.portal.com (sullivan - segall) (07/01/90)

> 
> There is a utility called Stat in the v2.0 of the Kramden utilities.
>It has a way to let you list all the semaphores in your system.  There
>are only 2 programs that I've seen that use there own semaphore and these
>are Tracksalve and some other program (I forget it;s's name).  How come
>more people don't use semaphrores?  Wouldn't they help out a lot in some
>areas?  I know that semaphorses in a Vax is useful for synchronizing tasks...
>Is this what they are used for on the Amiga? Would someone PLEASE elaborate?
> 
The Amiga tends to use Forbid() and Permit() to serve this purpose.  The 
good side of this is that you don't have to know what the name of the 
semaphore you want to allocate is.  (Sorry about the verb, I've been studying
German for too long.)  The bad side is that you basically have the equivalent 
of one system semaphore for every program.  As a result every task is blocked
from running when you really only need to block programs requesting the same
resource.  

Of course in many areas semaphore like operations are handled well.  Filelocks,
and library locks are examples.  Some misbehaved programs can cause quite a 
bit of trouble though by abusing these semaphores.

-kls

limonce@pilot.njin.net (Tom Limoncelli) (07/01/90)

In article <31309@cup.portal.com> Sullivan@cup.portal.com (sullivan - segall) writes:

> Someone asks:
> >  Why don't people use the Amiga semaphore routines more often?
> The Amiga tends to use Forbid() and Permit() to serve this purpose.  The 
> good side of this is that you don't have to know what the name of the 
> semaphore you want to allocate is.  (Sorry about the verb, I've been studying

I think you missed two other reasons.  First of all, the routines have
bugs in them and if you don't have the work-around you might will get
discouraged and stop using them.

Secondly, if you do read the RKM section on semaphores you'll notice
that it explains how to use them, but then says something like
	"Deadlocks can still occur if you're not careful, find a 
	good book on operating systems (like the Minix book) for more info."
Most people without a BA or BS in CS are going to read that and start
using Forbid() and Permit().

(Soapbox) This must be a bad week for me because I've come across 3
cases where a software development problem "happened" because the
programmers didn't have a good base in xxxx theory.  (where xxxx =
relational calculus (i.e. database), semaphore and disk scheduling)

(Joke mode) Well I only have to take 1 CS class in my last year (next
year) of college.  I'll try to ignore the theory so I can "fit in"
when I get to the job market.

-Tom
-- 
tlimonce@drew.edu      Tom Limoncelli
tlimonce@drew.uucp     +1 201 408 5389
tlimonce@drew.Bitnet
limonce@pilot.njin.net

brian@babbage.csus.edu (Brian Witt) (07/02/90)

In article <709.268c893f@desire.wright.edu> arc@desire.wright.edu writes:
>  There
>are only 2 programs that I've seen that use there own semaphore and these
>are Tracksalve and some other program (I forget it;s's name).  How come
>more people don't use semaphrores?  Wouldn't they help out a lot in some
>areas?  I know that semaphorses in a Vax is useful for synchronizing tasks...
>Is this what they are used for on the Amiga? Would someone PLEASE elaborate?
 
OK, SimCity on the Amiga uses semaphores.  When the Maps and Graphs screen
needs updating it lokks the simulators database, redraws the map, then
unlocks (V operation).  Great way to provide consistant results!! :-)
The application is user-time (ie, slow realtime), so someone can wait
if they need to without damaging results.  The critical section was
entered only ocassionally (about once every 15 seconds).

The lesson from the experience is:  make the "locking mechanism" as "light"
as possible.  Perhaps code like:  while(in_use) Delya(50L);  would work
just as well (ignoring race conditions).  Kids, don't do this at home.
(Please don't flame this paragraph. OK?)

Since the code was developed simutaneously for the Amiga and the
Macintosh, it was hard to get Amiga specific code in the simulator that
ran in the background.  In this case, it was more a problem of code
clutter than actual programmer ignorance.

BTW, to however wrote the Signal Semaphore package (I think Neil Katin):
very cute, very sneaky, very clever solution; I like it! :-) :-) :-)


> /Bryan
 

--- Laws seldom stop polititicans
--- brian witt                     uunet.uu.net!seer.UUCP!rael!aleks

limonce@pilot.njin.net (Tom Limoncelli) (07/03/90)

People have asked me to post the docs I have on semaphores.  I found
this in a very old directory on my hard drive.  I can't find a source,
but I'm sure it was posted to Usenet.  One of the files mentions that
the author got help from the people at C-A, so I assume it was written
by someone that isn't a C-A Employee.

-Tom
Here it is:

>>>>>>>>>>sem.doc<<<<<<<<<<
I've been looking through the Autodocs on message & signal semaphores
and I find them to be a little bit lacking (I know, this has been
mentioned before).  So I was hoping that I might clarify the
use of them just a bit.  These programs demonstrate what I think is
going on, I invite you all to try to find problems with them...  They seem
OK to me but semaphores in any O/S are a really touchy area.

----

Message based semaphores (usually refered to as just 'Semaphores') make use
of the Message sending/receiving/waiting protocols.  In order to use
them you must initialize a 'struct Semaphore'  if you examine just what
a struct Semaphore is you'll see that it is defined as

struct Semaphore {
       struct MsgPort sm_MsgPort;
       WORD sm_Bids;
}

(it's in <exec/semaphores.h> like all of the semaphore definitions).

To initialize it, you must allocate the memory for the structure and
then do all of the usual MsgPort initialization things.  Normally
CreatePort() does all of this for you but you can't use it as you have
do to a slightly different initialization for a semaphore.  See the
CreateSemaphore() function in the msgsem example.  You can make a
semaphore public by making its MsgPort public (i.e. giving the MsgPort
a name & priority and using AddPort() to add the port to the system list
of named ports).  You can then find such a semaphore by using the FindPort()
call... To remove the semaphore from the system you have do remove it from
the public port list using RemPort() (iff you added it to that list) and
then simply free the memory allocated for the structure.

Assuming you have created the Semaphore, to use it you must allocate a
message (to be used as your 'bid' for the semaphore) and port that this
message will be sent to.  Initialize the mn_ReplyPort field of your
message to point to your port.  You then use these two functions
to lock/unlock the semaphore.

Procure(Semaphore, BidMessage)
struct Semaphore *Semaphore;
struct Message *BidMessage;

       Procure() returns true if the semaphore can be locked for your
       use immediately.  If the semaphore cannot be locked, your
       bid is queued up and when it becomes free your BidMessage
       will be sent the the port you allocated (the one that nm_ReplyPort
       in the BidMessage is supposed to point to).  So if you need
       to get the Semaphore and you can't go on any further without
       it you must do something like

       if (!Procure(semaphore,message)) {
               WaitPort(message->mn_ReplyPort);
               GetMsg(message->nm_ReplyPort);
       }

       ... put code that needs the semaphore here ...

       This assumes that there is only one semaphore using this port
       for it's replies.  Otherwise you have to be more complicated.

Vacate(Semaphore)
struct Semaphore *Semaphore;

       Vacate() unlocks the semaphore so that some other Procure()
       will succeed or if there is an outstanding bid then the
       bid message will sent to the appropriate port.

       So much for straight Semaphores.  Now onto SignalSemaphores.

----

SignalSemaphores seem much easier to use on the surface only they
are slightly broken which makes up for this.  The AddSemaphore(),
RemSemaphore() and FindSemaphore() calls all need special attention
as they don't work as advertised in the Autodocs.  Other than this
difficulty, signal semaphores are very easy to deal with as
there are no painful initialization rituals to remember as with
message semaphores above... just allocate enough memory for the
SignalSemaphore and you're off to the races.

InitSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;

       Initializes a signal semaphore structure.  Use this function
       for "private" semaphores (i.e. known only to tasks that
       have easy access to the creator's memory).

AddSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;

       Adds the semaphore to the system list of semaphores.  You
       must fill in the ss_Link.ln_{Type,Name,Pri} fields before
       calling this.  AddSemaphore() calls InitSemaphore() so
       you don't need to do call this yourself if you use AddSemaphore().

       N.B.  The Exec version of this function seems to be broken.
       Use Dale's "hand crafted" version instead.  (it's just a
       InitSemaphore() call followed by an atomic Enqueue on the
       system signal semaphore list).  See example.


RemSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;

       Removes the given semaphore from the system list of public
       semaphores.

       N.B. The amiga.lib and c[32].lib bindings for this function
       are broken.  You must include your own bindings for this
       to work.  See example.


struct SignalSemaphore *FindSemaphore(name)
char *name;

       Search the system list for semaphores for one with the given
       name.  Returns a pointer to the semaphore if one is found,
       NULL otherwise.

       N.B. The amiga.lib and c[32].lib bindings for this function
       are broken.  You must include your own bindings for this
       to work.  See example.


ObtainSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;

       This function locks the given semaphore for your use.  If the
       semaphore is currently in use by someone else it blocks until
       it is Release'd by the current owner.  A nesting count is
       maintained if you try to Obtain a semaphore that you already
       have.

ReleaseSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;

       This function frees the given semaphore for use by someone
       else.  If you Obtained the semaphore more than once the
       the nesting count is simply decremented rather than
       actually Releasing the semaphore.  Bad things happen if
       you Release more times than you Obtain.


AttemptSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;

       This function tries to Obtain the semaphore provided.  If this
       can be done it locks the semaphore and returns true.  If the
       semaphore is currently in use by someone else it returns false.
       Use this function if you don't want to block your task waiting
       for a semaphore.


ObtainSemaphoreList(SemaphoreList)
struct SemaphoreList *SemaphoreList;

ReleaseSemaphoreList(SemaphoreList)
struct SemaphoreList *SemaphoreList;

       Haven't played with these two yet... They're used for locking
       several semaphores in one atomic action.  This ability can
       be used to prevent deadlock.

----

Note:
       The Kernel doesn't seem to do any kind of deadlock prevention
       or recovery.  This means you have to decide for yourself if
       deadlock is an issue in your application.  There are several
       good books which deal with deadlock avoidance and so forth
       so I won't go into that here.

>>>>>>>>>>Makefile<<<<<<<<<<
CFLAGS= +L

all: msgsem sigsem

msgsem:        msgsem.o
       ln -o msgsem msgsem.o -lc32

sigsem:        sigsem.o
       ln -o sigsem sigsem.o -lc32

>>>>>>>>>>msgsem.c<<<<<<<<<<
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/ports.h>
#include <exec/semaphores.h>
#include <exec/memory.h>

struct MsgPort *CreatePort();
struct MsgPort *FindPort();
struct XSemaphore *CreateSemaphore();
void DeleteSemaphore();
void *AllocMem();
void cleanup();

struct XSemaphore {
       struct Semaphore s;
       WORD Users;
};

struct MsgPort *port = 0;
struct XSemaphore *sem = 0;
struct Message msg;

/* I made this extended semaphore so that there is an easy way to
 * keep track of when it is safe to delete it.  If anyone can think
 * of a better way to do this, I'd love to hear it.
 */

extern int Enable_Abort;

main()
{
       int i;
       Enable_Abort = 0;

       /* the existance check/creation must be atomic --> Forbid/Permit */
       Forbid();
       if (!(sem = (struct XSemaphore *)FindPort("my semaphore")))
               sem = CreateSemaphore("my semaphore", 0);
       else
               sem->Users++;

       Permit();

       if (!sem) {
               printf("Error, can't find *or* create semaphore\n");
               cleanup();
               exit(100);
       }

       port = CreatePort(0,0);
       if (!port) {
               printf("Error, can't create my reply port\n");
               cleanup();
       }

       msg.mn_Node.ln_Type = NT_MESSAGE;
       msg.mn_Length       = sizeof(struct Message);
       msg.mn_ReplyPort    = port;

       /* for P & V fans, the Procure & Vacate names are mnemonic */
       /*                     -         -                         */

       for (i=0;i<5;i++) {
               if (!Procure(sem, &msg)) {
                       WaitPort(port); /* wait for the message to come */
                       GetMsg(port);   /* get it */
               }

               /* we now have exclusive access */

               printf("\nTask $%06x owns the semaphore\n",FindTask(0));

               /* pretend to so some action requiring semaphore */
               Delay(1 + (rand()&31));

               printf("\t\t...semaphore now released\n");

               /* yield control to someone else */
               Vacate(sem);

               /* pretend to so some action not requiring semaphore */
               Delay(1 + (rand()&31));

       }

       cleanup();

}

void cleanup()
{
       if (port) {
               DeletePort(port);
               port = 0;
       }

       /*
        * we'd like to use the semaphore to lock out other users here
        * but we'd have to somehow P and then not do a V but delete
        * the port instead for this to work... That hurts me more than
        * the Forbid() Permit() pair...
        */

       if (sem) {
               /* the user check/delete must be atomic --> Forbid/Permit */

               Forbid();
               if (--sem->Users == 0)
                       DeleteSemaphore(sem);
               Permit();

               sem = 0;
       }
}

struct XSemaphore *CreateSemaphore(name,pri)
char *name;
int pri;
{
       struct XSemaphore *s;
       char *buf;

       s = AllocMem(sizeof(struct XSemaphore), MEMF_PUBLIC|MEMF_CLEAR);
       if (!s)
               return(0);

       s->s.sm_Bids = -1;
       NewList(&s->s.sm_MsgPort.mp_MsgList);
       s->s.sm_MsgPort.mp_Flags        = PA_IGNORE;
       s->s.sm_MsgPort.mp_Node.ln_Type = NT_SEMAPHORE;
       s->s.sm_MsgPort.mp_Node.ln_Pri  = pri;
       s->Users                        = 1;

       /* Note that the name must be copied as the original creator
        * of the semaphore might exit.  We can't leave a pointer to
        * the original data segment lying around after the program
        * has exited.
        */
       if (name) {
               buf = AllocMem(strlen(name)+1, MEMF_PUBLIC);
               if (!buf) {
                       FreeMem(s, sizeof(struct XSemaphore));
                       return(0);
               }
               strcpy(buf,name);
               s->s.sm_MsgPort.mp_Node.ln_Name = buf;
               AddPort(s);
       }
       return(s);
}

void DeleteSemaphore(s)
struct XSemaphore *s;
{
       char *name;

       if (!s) return;

       name =  s->s.sm_MsgPort.mp_Node.ln_Name;

       if (name) {
               RemPort(s);     /* remove from list of public semaphores */
               FreeMem(name,strlen(name)+1);
       }

       FreeMem(s, sizeof(struct XSemaphore));
}

>>>>>>>>>>sigsem.c<<<<<<<<<<
/*
 * This program plays around with signal semaphores...
 *
 * Thanks to C-A for providing the new bindings & AddSemaphore code
 *
 */<

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/ports.h>
#include <exec/semaphores.h>
#include <exec/memory.h>
#include <exec/execbase.h>

struct XSSemaphore {
       struct SignalSemaphore s;
       WORD Users;
};

void *AllocMem();
void cleanup();
void DeleteSSemaphore();
struct SignalSemaphore *myFindSemaphore();
struct XSSemaphore *CreateSSemaphore();

struct XSSemaphore *sem = 0;

/* I made this extended semaphore so that there is an easy way to
 * keep track of when it is safe to delete it.  If anyone can think
 * of a better way to do this, I'd love to hear it.
 */

extern int Enable_Abort;

main()
{
       int i;
       Enable_Abort = 0;

       /* the existance check/creation must be atomic --> Forbid/Permit */

       Forbid();

       if (!(sem = (struct XSSemaphore *)myFindSemaphore("sigSemaphore")))
               sem = CreateSSemaphore("sigSemaphore",0);
       else
               sem->Users++;

       Permit();

       if (!sem) {
               printf("Error, can't find *or* create semaphore\n");
               cleanup();
               exit(100);
       }

       for (i=0;i<5;i++) {

               /* get use of the semaphore */
               ObtainSemaphore(sem);

               /* we now have exclusive access */

               printf("\nTask $%06x owns the semaphore\n",FindTask(0));

               /* pretend to so some action requiring semaphore */
               Delay(1 + (rand()&31));

               printf("\t\t...semaphore now released\n");

               /* yield control to someone else */
               ReleaseSemaphore(sem);

               /* pretend to so some action not requiring semaphore */
               Delay(1 + (rand()&31));

       }

       cleanup();
}

void cleanup()
{
       if (sem) {
               /* the user check/delete must be atomic --> Forbid/Permit */

               Forbid();
               if (--sem->Users == 0)
                       DeleteSSemaphore(sem);
               Permit();

               sem = 0;
       }
}

struct XSSemaphore *CreateSSemaphore(name,pri)
char *name;
int pri;
{
       struct XSSemaphore *sem;
       char *buf;

       sem = AllocMem(sizeof(struct XSSemaphore), MEMF_PUBLIC|MEMF_CLEAR);

       if (!sem) return(0);

       sem->s.ss_Link.ln_Type = NT_SIGNALSEM;
       sem->s.ss_Link.ln_Pri  = pri;

       /* Note that the name must be copied as the original creator
        * of the semaphore might exit.  We can't leave a pointer to
        * the original data segment lying around after the program
        * has exited.
        */
       if (name) {
               buf = AllocMem(strlen(name)+1, MEMF_PUBLIC);
               if (!buf) {
                       FreeMem(sem, sizeof(struct XSSemaphore));
                       return(0);
               }
               strcpy(buf,name);
               sem->s.ss_Link.ln_Name = buf;
               myAddSemaphore(sem);
       }
       else
               InitSemaphore(sem);

       sem->Users = 1;

       return(sem);
}

void DeleteSSemaphore(sem)
struct XSSemaphore *sem;
{
       char *name;

       if (!sem) return;

       name = sem->s.ss_Link.ln_Name;

       if (name) {
               myRemSemaphore(sem);
               FreeMem(name, strlen(name) + 1 );
       }

       FreeMem(sem, sizeof(struct XSSemaphore));
}


/* The bindings for "AddSemaphore" are broken in 1.2 Amiga.lib
 *
 * Dale's handcrafted AddSemaphore().
 */

myAddSemaphore(ss)
struct SignalSemaphore *ss;
{
    extern struct ExecBase *SysBase;

    InitSemaphore(ss);
    Forbid();
    Enqueue(&SysBase->SemaphoreList,ss);
    Permit();
}

/* The "C" interface code for the following semaphore routines is broken in
 * Amiga.lib and in the Aztec C release 3.4a.
 *
 * @ Lattice people should cut and paste the assembler into a separate file.
 */

#if AZTEC_C
#asm
; The exec.library function "AddSemaphore" is broken in KickStart rel. 33.180
;
; The Aztec bindings think that they should be using a0 to pass the
; argument instead of a1.  This is likely the problem with the Lattice
; bindings.  The Exec AddSemaphore function seems to be just plain broken.
;
;              -Rico

        XREF    _SysBase
        XREF    _LVOFindSemaphore
       XREF    _LVORemSemaphore


       XDEF    _myFindSemaphore
       XDEF    _myRemSemaphore

_myFindSemaphore:
       move.l  4(sp),a1
        move.l         _SysBase,a6
       jmp     _LVOFindSemaphore(a6)

_myRemSemaphore:
       move.l  4(sp),a1
        move.l         _SysBase,a6
       jmp     _LVORemSemaphore(a6)
#endasm
#endif
-- 
tlimonce@drew.edu      Tom Limoncelli
tlimonce@drew.uucp     +1 201 408 5389
tlimonce@drew.Bitnet
limonce@pilot.njin.net