[comp.sys.amiga.programmer] Message Ports

bart@asgard.pub.uu.oz.au (John Butcher) (05/25/91)

Ive been trying to do message ports, but I havent had lots of success, my ports
wont get properly recognized by name.  Below small test program I wrote :

main( argc, argv )
  int argc;
  char *argv[];
{
  struct MsgPort *mp;

  mp = FindPort( argv[1] );
  if ( mp == NULL )                            /* No port with that name */
  {
    mp = CreatePort( argv[1], 0 );                    /* so create one ! */
    printf("Created \"%s\" at 0x%0x\n", argv[1], mp );
  }
  else                                           /* found the given port */
  {
    printf("Found \"%s\" at 0x%0x\n", argv[1], mp );
    DeletePort( mp );                                    /* so remove it */
  }
}

And here is some test runs.... ( with added comments ;-)

2.RAMB0:> port crud        
Created "crud" at 0x208d28        Yay, it created ok !!
2.RAMB0:> port anticrud     
Found "anticrud" at 0x208d28      Whats this, I thought I called you crud !
2.RAMB0:> port crud        
Created "crud" at 0x208d28        Yep, well it created ok
2.RAMB0:> port zzzz        
Found "zzzz" at 0x208d28          But a different name is found at the address

So....Can anyone tell me what is going on ??

-----------------------------------------------------------------------------
 John Butcher : bart@asgard.pub.uu.oz.au
                ..!munnari!eyrie.oz.au!asgard!bart
"I'm only paranoid 'cos everyone's against me !"  -  Frank Burns             

nj@magnolia.Berkeley.EDU (Narciso Jaramillo) (05/26/91)

In article <BQAcp*wk@asgard.pub.uu.oz.au> bart@asgard.pub.uu.oz.au (John Butcher) writes:

> Ive been trying to do message ports, but I havent had lots of success, my 
> ports wont get properly recognized by name.  Below small test program I 
> wrote :

> main( argc, argv )
> int argc;
> char *argv[];
> {
>   struct MsgPort *mp;

>   mp = FindPort( argv[1] );
>   if ( mp == NULL )                            /* No port with that name */
>   {
>     mp = CreatePort( argv[1], 0 );                    /* so create one ! */
>     printf("Created \"%s\" at 0x%0x\n", argv[1], mp );
>   }
>   else                                           /* found the given port */
>   {
>     printf("Found \"%s\" at 0x%0x\n", argv[1], mp );
>     DeletePort( mp );                                    /* so remove it */
>   }
> }

>   2.RAMB0:> port crud        
>   Created "crud" at 0x208d28        Yay, it created ok !!
>   2.RAMB0:> port anticrud     
>   Found "anticrud" at 0x208d28      Whats this, I thought I called you crud !

What's probably happening is that CreatePort doesn't copy the string
you pass to it.  When you create "crud", mp->mp_Node.ln_Name gets
argv[1], which currently points to "crud."  Your program then exits.
When you invoke the program again, argv[1] happens to be in the same
place, and so mp->mp_node.ln_Name points to whatever name you put on
the command line in the second invocation.  This makes the name of the
message port magically change to the name you give it the second time
around (i.e. the new argv[1]).  So the program thinks the port name is
the same as the one you passed, and it finds it.

The only way around this that I can think of is to AllocMem space for
a new string when you create a port, but don't free it when you exit;
free it only after you delete the port the next time you invoke the
program with that port name.  (If you AllocMem some memory in one
program, can you FreeMem it in another?  I assume so, as long as it's
MEMF_PUBLIC.)

In other words:

--
void main(int argc, char *argv[]) {

  struct MsgPort *mp;
  char *new;

  mp = FindPort(argv[1]);
  if (mp == NULL) {
    new = AllocMem(strlen(argv[1])+1, MEMF_PUBLIC); /* need 1 byte for \0 */
    if (!new) {
      die_horribly();
    }
    strcpy(new, argv[1]);
    mp = CreatePort(new, 0);
    printf("Created \"%s\" at 0x%0x\n", new, mp);
  } else {
    printf("Found \"%s\" at 0x%0x\n", argv[1], mp);
    Forbid(); /* just in case--may not be necessary */
    FreeMem(mp->mp_Node.ln_Name, strlen(mp->mp_Node.ln_Name)+1);
    DeletePort(mp);
    Permit();
  }

}    
--

That solution is kind of gross, but then again I don't think ports
were meant to hang around after a program exited.  Do you really need
a port that lasts after your program's termination, or was this just
for the test program?


nj

black@beno.CSS.GOV (Mike Black) (05/26/91)

>
>That solution is kind of gross, but then again I don't think ports
>were meant to hang around after a program exited.  Do you really need
>a port that lasts after your program's termination, or was this just
>for the test program?
>

Ports tie themselves to the invoking task and therefore are definitely
NOT meant to hang around after termination.  His program works just
fine if modified slightly so that it hangs around for a while after
creating the port so you can run the program from another window to
try and find it (WITHOUT deleting it).  Always let the program that
creates the port delete it.
Mike...

--
-------------------------------------------------------------------------------
: usenet: black@beno.CSS.GOV   :  land line: 407-494-5853  : I want a computer:
: real home: Melbourne, FL     :  home line: 407-242-8619  : that does it all!:
-------------------------------------------------------------------------------

bart@asgard.pub.uu.oz.au (John Butcher) (06/01/91)

In article <NJ.91May25224115@magnolia.Berkeley.EDU>, Narciso Jaramillo writes:

> In article <BQAcp*wk@asgard.pub.uu.oz.au> bart@asgard.pub.uu.oz.au (John Butcher) writes:

A note on the side, totally unrelated to this group, but ..... Has anyone else
had Arn V0.68f stuff up article numbers like the above ?

[ solution to problem ]

Thanks muchly, Ive already been given the solution, and tried to cancel the
article, but it seems to have disappeared from my machine :-(

> That solution is kind of gross, but then again I don't think ports
> were meant to hang around after a program exited.  Do you really need
> a port that lasts after your program's termination, or was this just
> for the test program?

Basically just a test, but I was thinking of a way to get stuff to hang around
after the program quits, so when you run it again, the stuff is there, and
can be used again !! - Is there another ( better ) way to do this ??

-----------------------------------------------------------------------------
 John Butcher : bart@asgard.pub.uu.oz.au
                ..!munnari!eyrie.oz.au!asgard!bart
"'Racket'??  That's BRAHMS...   BRAHMS' THIRD RACKET!!!" - Basil Fawlty      

bart@asgard.pub.uu.oz.au (John Butcher) (06/01/91)

In article <49659@seismo.CSS.GOV>, Mike Black writes:

> >
> >That solution is kind of gross, but then again I don't think ports
> >were meant to hang around after a program exited.  Do you really need
> >a port that lasts after your program's termination, or was this just
> >for the test program?
> >
> 
> Ports tie themselves to the invoking task and therefore are definitely
> NOT meant to hang around after termination.  His program works just
> fine if modified slightly so that it hangs around for a while after
> creating the port so you can run the program from another window to
> try and find it (WITHOUT deleting it).  Always let the program that
> creates the port delete it.

Hmmm, I was directed to some PD source for some handlers ( Sun mouse and
click-to-front I think, could be wrong ), which use a message port to store
a pointer to some stuff, so when you run it the first time, it creates the
port, then subseqent runs find look for the port, and can use it if it's there
( to kill the program ), so the 1st time you run it, it installs the handler,
the second time, cos the port is found, it kills it, etc
I seem to remember the code using the "task" address to store a pointer to it's
own AllocMem()'d data, so is there anything wrong with doing this, it _DOES_
work, I dont know how good the practice is, the question is, is it possible
for this sort or program to break, and if so, what are the alternatives ?

> Mike...
> 
> --
> -------------------------------------------------------------------------------
> : usenet: black@beno.CSS.GOV   :  land line: 407-494-5853  : I want a computer:
> : real home: Melbourne, FL     :  home line: 407-242-8619  : that does it all!:
> -------------------------------------------------------------------------------
               ^^^^^^^^^
               Not to be confused with Melbourne Australia, _MY_ real home ;-)

-----------------------------------------------------------------------------
 John Butcher : bart@asgard.pub.uu.oz.au
                ..!munnari!eyrie.oz.au!asgard!bart
"'Racket'??  That's BRAHMS...   BRAHMS' THIRD RACKET!!!" - Basil Fawlty      

drysdale@cbmvax.commodore.com (Scott Drysdale) (06/06/91)

In article <BQAcp*wk@asgard.pub.uu.oz.au> bart@asgard.pub.uu.oz.au (John Butcher) writes:
>Ive been trying to do message ports, but I havent had lots of success, my ports
>wont get properly recognized by name.  Below small test program I wrote :
>
>main( argc, argv )
>  int argc;
>  char *argv[];
>{
>  struct MsgPort *mp;
>
>  mp = FindPort( argv[1] );
>  if ( mp == NULL )                            /* No port with that name */
>  {
>    mp = CreatePort( argv[1], 0 );                    /* so create one ! */

CreatePort() simply points to the name you give it (argv[1] in your case).
you want to do something like this:

	char *name;
	name = AllocMem(strlen(argv[1]) + 1, MEMF_PUBLIC);
	strcpy(name, argv[1]);
	mp = CreatePort(name, 0);

*note* do NOT free(name) - you want the port to live forever (or until
you delete it, whichever comes first).

>    printf("Created \"%s\" at 0x%0x\n", argv[1], mp );
>  }
>  else                                           /* found the given port */
>  {
>    printf("Found \"%s\" at 0x%0x\n", argv[1], mp );

	FreeMem(mp->mp_Node.ln_Name, strlen(mp->mp_Node.ln_Name) + 1);

>    DeletePort( mp );                                    /* so remove it */
>  }
>}
>
>And here is some test runs.... ( with added comments ;-)
>
>2.RAMB0:> port crud        
>Created "crud" at 0x208d28        Yay, it created ok !!

seems to behave as you desire.  the port is allocated and initialized.
however, the port's name points to argv[1], which is transient.

>2.RAMB0:> port anticrud     
>Found "anticrud" at 0x208d28      Whats this, I thought I called you crud !

this time it runs, the port's name still points to the memory for argv[1],
which just happens to be the same physical address as before.  ie, the
port's name now points to the name on the command line, so of course it'll
find the port.

>2.RAMB0:> port crud        
>Created "crud" at 0x208d28        Yep, well it created ok

ad nauseum.

>2.RAMB0:> port zzzz        
>Found "zzzz" at 0x208d28          But a different name is found at the address

>So....Can anyone tell me what is going on ??

> John Butcher : bart@asgard.pub.uu.oz.au

  --Scotty
-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Scott Drysdale           Software Engineer
Commodore Amiga Inc.     UUCP {allegra|burdvax|rutgers|ihnp4}!cbmvax!drysdale
		         PHONE - yes.
"Have you hugged your hog today?"
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

phorgan@cup.portal.com (Patrick John Horgan) (06/07/91)

In article <BQAcp*wk@asgard.pub.uu.oz.au> bart@asgard.pub.uu.oz.au (John Butche
r) writes:
>Ive been trying to do message ports, but I havent had lots of success, my port
s
>wont get properly recognized by name.  Below small test program I wrote :

Here I have an assembler version of a Create/Delete Port pair 
that fix the problem at the "system" level.  The Create gets
it's own memory for the string, and Delete frees it up. .
It's pretty generic Manx assembler, but it'll need some cludging
for other assemblers I'm sure.  It's even simpler to do this
in C.

First is a neccessary include file:

stktypes.i
~~~~~~~~~~~~cut here~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
;:ts=8
    IFND EXEC_ST_TYPES_I
EXEC_ST_TYPES_I SET 1

ST_STRUCTURE	MACRO
\1		EQU	0
SOFFSET		SET	\2
 ENDM

ST_FRAME	MACRO
\1		EQU	0
SOFFSET		SET	\2
 ENDM

ST_BOOL		MACRO
SOFFSET		SET	SOFFSET-2
\1		EQU	SOFFSET
 ENDM

ST_BYTE        MACRO
SOFFSET		SET	SOFFSET-1
\1		EQU	SOFFSET
 ENDM

ST_UBYTE	MACRO
SOFFSET		SET	SOFFSET-1
\1		EQU	SOFFSET
 ENDM

ST_WORD		MACRO
SOFFSET		SET	SOFFSET-2
\1		EQU	SOFFSET
 ENDM

ST_UWORD	MACRO
SOFFSET		SET	SOFFSET-2
\1		EQU	SOFFSET
 ENDM

ST_SHORT	MACRO
SOFFSET		SET	SOFFSET-2
\1		EQU	SOFFSET
 ENDM

ST_USHORT	MACRO
SOFFSET		SET	SOFFSET-2
\1		EQU	SOFFSET
 ENDM

ST_LONG		MACRO
SOFFSET		SET	SOFFSET-4
\1		EQU	SOFFSET
 ENDM

ST_ULONG	MACRO
SOFFSET		SET	SOFFSET-4
\1		EQU	SOFFSET
 ENDM

ST_FLOAT	MACRO
SOFFSET		SET	SOFFSET-4
\1		EQU	SOFFSET
 ENDM

ST_APTR		MACRO
SOFFSET		SET	SOFFSET-4
\1		EQU	SOFFSET
 ENDM

ST_CPTR		MACRO
SOFFSET		SET	SOFFSET-4
\1		EQU	SOFFSET
 ENDM

ST_RPTR		MACRO
SOFFSET		SET	SOFFSET-2
\1		EQU	SOFFSET
 ENDM

ST_STRUCT	MACRO
SOFFSET		SET	SOFFSET-\2
\1		EQU	SOFFSET
 ENDM

ST_LABEL	MACRO
\1		EQU	SOFFSET
 ENDM

    ENDC EXEC_ST_TYPES_I

~~~~~~~~~~~cut here~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now the code follows:
~~~~~~~~~~~cut here~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;:ts=8
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*	CreatePort(char *name, long pri)
*
*	Patrick J. Horgan   pjh70@zeus.ras.amdahl.com
*
*	Creates an Amiga MsgPort.  This is a reentrant program.  The usual
*	amiga.lib CreatePort doesn't allocate memory for the name of the 
*	port.  A consequence of this is that routines that call CreatePort
*	many times will, at best, have all the ports named the same
*	as the last one made.  The worst case would be if the string 
*	passed for the name was an automatic variable, in which case it
*	would contain garbage when the stack was reclaimed!
*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*CreatePort(name, pri)
*DeletePort(mp)
*register struct MsgPort *mp;


    NOLIST
	include 'exec/types.i'
	include 'stktypes.i'
	include 'exec/nodes.i'
	include 'exec/lists.i'
	include	'exec/memory.i'
	include 'exec/ports.i'
	include 'exec/libraries.i'
    LIST

* A useful macro

call	MACRO
	CALLLIB	_LVO\1
 ENDM

* Our external references...

	EXTERN_LIB	AddPort
	EXTERN_LIB	AllocMem
	EXTERN_LIB	AllocSignal
	EXTERN_LIB	FindTask
	EXTERN_LIB	FreeMem
	EXTERN_LIB	FreeSignal
	EXTERN_LIB	RemPort

 ST_FRAME myframe,0
 	ST_APTR	ST_MP
 ST_LABEL myfrsize

*CreatePort(name, pri)
* Here's what's on the stack after my initial link.

 STRUCTURE ARGS,0
 	ULONG	olda5		Contents of a5 before link.
	APTR	retaddr		Where we will rts to.
	APTR	name		The name of the new port.
	ULONG	priority	The priority of the new port.
 LABEL ARGS_SIZE

* Make me visable

	public _CreatePort

	far	code

* And away we go...

_CreatePort:
	link	a5,#myfrsize		Set up space for the stk-frame.
	movem.l	a2-a3/a6/d3,-(sp)	Save registers we trash.
	move.l	4,a6
	move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1 We need mem like dis!
	move.l	#MP_SIZE,d0		And it's dis size.
	call	AllocMem		Get it.
	tst.l	d0			Did we get it?
	beq	err3			Abort...
	move.l	d0,ST_MP(a5)		Save the pointer...
	movea.l	d0,a3			    and get a work copy.
	tst.l	name(a5)		Is there a name?
	bne	donm			Yep...do the name.
	clr.l	LN_NAME(a3)		No name.
	bra	nonm			Skip the name jazz.

* There's a name, so count the chars for the AllocMem.

donm	clr.l	d0			This is our string length counter.
	move.l	name(a5),a1		a1 points at the name.

* Set up's done, countem.

countem	addq.l	#1,d0			Count the chars
	move.b	(a1)+,d1		Get the char.
	bne.s	countem			If not EOS keep goin'.
	addq	#4,d0			Get memory for the length.
	move.l	d0,d3			Save a copy.

* Now allocate that much memory.

	move.l	#MEMF_PUBLIC!MEMF_CLEAR,d1 Dese are da requirements.
	call	AllocMem		Get the mem.
	tst.l	d0			Did we get it?
	beq	err2			Nah, go free resources.
	add.l	#4,d0			Skip the length.
	move.l	ST_MP(a5),a3		ReBase the port.
	move.l	d0,LN_NAME(a3)		Stash the name.
	movea.l	d0,a0			Base the new string mem.
	move.l	d3,-4(a0)		Save the length.
	movea.l	name(a5),a3		Point at the passed name.

* We're set up for the copyin' so copy it.

copyem	move.b	(a3)+,(a0)+		Copy from da ol' to da new.
	bne.s	copyem			Copy to EOS.

nonm	move.l	ST_MP(a5),a3		Base the new MsgPort in a3.
	clr.l	LN_SUCC(a3)		Clear the node links.
	clr.l	LN_PRED(a3)
	move.b	priority+3(a5),LN_PRI(a3) set the node priority.
	clr.l	d0			Get a zero
	move.b	d0,MP_FLAGS(a3)		Clear the flags.
	movea.l	d0,a1			a1 is arg for FindTask(0).
	call	FindTask		Who are we?
	move.l	d0,MP_SIGTASK(a3)	This is who gets the messages.
	move.l	#-1,d0			We don't care which signal.
	call	AllocSignal		Get a signal.
	tst.l	d0
	bmi	err1			Oops no signal, free resources 
*                                           and abort.
	move.b	d0,MP_SIGBIT(a3)	Here's our sigbit.
	move.l	a3,a1			Put the pointer to the port in
	call	AddPort			    a1 as argument for AddPort.
	move.l	a3,d0			Here's our return value.
exit	movem.l	(sp)+,a2-a3/a6/d3	Restore registers we trash.
	unlk	a5			Set up space for the stk-frame.
	rts

* Free the Memory for the Name...

err1	move.l	ST_MP(a5),a3
	move.l	LN_NAME(a3),a1		Point at the name.
	suba.l	#4,a1			Back up to the size.
	move.l	(a1),d0			Got the size.
	call	FreeMem

* Free the Memory for the MsgPort...

err2	move.l	ST_MP(a5),a1		We Free dis
	move.l	#MP_SIZE,d0		and it's dis size.
	call	FreeMem

* Return zero for failure.

err3	clr.l	d0			Return null for failure.
	bra	exit


*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*	DeletePort(MsgPort *dp_port)
*
*	Patrick J. Horgan   pjh70@zeus.ras.amdahl.com
*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 STRUCTURE DP_ARGS,0
 	ULONG	savea3			We stash a3.
	APTR	retadr			Where we will rts to.
	APTR	dp_port 		The port we will delete.
 LABEL DP_ARGS_SIZE

	public	_DeletePort
_DeletePort
	move.l	a3,-(a7)
	movea.l	dp_port(a7),a3		Point at the port.

* Remove the port from system lists.

	movea.l	a3,a1			Point at the port.
	call	RemPort

* Free the signal.

	clr.l	d0
	or.b	MP_SIGBIT(a3),d0	Here's our sigbit.
	call	FreeSignal

* Free the name...

	tst.l	LN_NAME(a3)		Is there a name?
	beq	dp_nonm
	move.l	LN_NAME(a3),a1		Point at the name.
	suba.l	#4,a1			Back up to the size.
	move.l	(a1),d0			Got the size.
	call	FreeMem

* Free the Memory for the MsgPort...

dp_nonm	movea.l	a3,a1			Point at the port.
	move.l	#MP_SIZE,d0		and it's dis size.
	call	FreeMem
	move.l	(a7)+,a3
dt_exit	rts

	end

robbel@fwi.uva.nl (Robert Belleman) (06/07/91)

drysdale@cbmvax.commodore.com (Scott Drysdale) writes:
>In article <BQAcp*wk@asgard.pub.uu.oz.au> bart@asgard.pub.uu.oz.au (John Butcher) writes:
>>been trying to do message ports, but I havent had lots of success, my ports
>>wont get properly recognized by name.  Below small test program I wrote :

[small test program deleted]

>CreatePort() simply points to the name you give it (argv[1] in your case).
>you want to do something like this:
>
>	char *name;
>	name = AllocMem(strlen(argv[1]) + 1, MEMF_PUBLIC);
>	strcpy(name, argv[1]);
>	mp = CreatePort(name, 0);
>
>*note* do NOT free(name) - you want the port to live forever (or until
>you delete it, whichever comes first).

I think that's dirty code.

Say, as another example like this, I'd want to change the name of a task,
_permanently_ ;
(hold on; following is all from memory)

main(int argc, char *argv[])
{
	struct *Task mytask;

	mytask = FindTask(NULL);			/* find _this_ task	*/
	mytask->tc_Node.ln_Name = argv[1];
}

... would obviously not work for the same reason as John's code.

But if I would change this to what Scot suggests (allocating memory for the
name, copying argv[1] to that memory and putting the name pointer to that and
NOT freeing anything), this would eat memory as I won't be able to free() it
anymore after my program exits! Even when the task exits!

How would you handle this situation?

>> John Butcher : bart@asgard.pub.uu.oz.au

>  --Scotty
>-- 
>=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
>Scott Drysdale           Software Engineer
>Commodore Amiga Inc.     UUCP {allegra|burdvax|rutgers|ihnp4}!cbmvax!drysdale
>		         PHONE - yes.
>"Have you hugged your hog today?"
>=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

-- Rob
 Robert Belleman
 robbel@fwi.uva.nl

-- 
 ______________________________________________________________________
/ Robert Belleman, University of Amsterdam                             \
|  robbel@fwi.uva.nl                                                    |
|  robbel@nki.nl                                                        |