Welcome, Guest. Please login or register.

Author Topic: Why doesn't this code starts automatically (full example with ports and message)...Also SAS linking  (Read 3970 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline JoseTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2871
    • Show only replies by Jose
Ok, I resourt to ask you why this doesn't work.   :-o
This painfully was stripped down from some program I'm doing, or should I say, trying to...

Here's the deal. Two programs, the MainTask and the OtherProcess. MainTask loads and creates the OtherProcess, wich is compiled sperately, from Ram: using CreateNewProc() (or CreateProc() wich older AOS versions). After loading OtherProcess Maintask sets up a message and a port to receive a reply.

The problem is the MainTask simply stops and hangs and I can't close the window. Given the code it should stop print a message and exit if it doesn't find the OtherProcess port. So I take it it finds it? But it just stops and the OtherProcess doesn't even output the initial message.
I managed to make it work like this. Runing the OtherProcess first from workbench(haven't tried from another shell but i guess it should work too) and then running the MainTask.
But in this case two instances of OtherProcess are running right?

So I take it that the MainTask is missing something to make the OtherProcess run. I wanted also know what's missing for it to display the messages in the same Window as the MainTask, cause that's what was intended when I wrote the code.

Here's the code for both, no clean up is included for simplicity, don't bother I just want to know why it doesn't work, my main program has cleanup for this part of the ini process.

MainTask

Code: [Select]

#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <exec/execbase.h>
#include <exec/types.h>
#include <exec/ports.h>
#include <exec/exec.h>
#include <utility/utility.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>
#include <stdio.h>
#include <stdlib.h>

struct Library *UtilityBase;

struct MsgPort *ReplyPort;
struct MsgPort *OtherProcessPort;

BPTR OtherProcessSegList = 0;

struct Message_to_OtherProcess
  { struct Message MesstoOP;
    struct Task *MainTask;
    struct Task *OtherProcess;
  };

struct Message_to_OtherProcess *Message_to_OtherProcess, *OtherProcessResponse;

struct Task *MainTask; /*This task*/
struct Task *OtherProcess;



int main (int argc, char **argv)
{                
 extern struct ExecBase *SysBase;
 
 char *OtherProcessName = &quot;Ram:OtherProcess&quot;;
 struct MsgPort *OtherProcess35;
 struct Process *OtherProcess;
 BPTR MainTaskOutputHandle;
 
 if (!(Message_to_OtherProcess  = (struct Message_to_OtherProcess *)AllocMem (sizeof(Message_to_OtherProcess),MEMF_PUBLIC|MEMF_CLEAR)))
   {printf (&quot;Couldn't allocate memory for Message to OtherProcess\n&quot;);
    exit (0);}
 
 if (!(ReplyPort =  CreatePort (0,0)))
   {printf (&quot;Couldn't create ReplyPort\n&quot;);
    exit (0);}
 Message_to_OtherProcess->MesstoOP.mn_ReplyPort = ReplyPort;
 
 
 if (!(OtherProcessSegList=LoadSeg(OtherProcessName)))
      {printf (&quot;Couldn't find OtherProcess\n&quot;);
       exit (0);}

 MainTaskOutputHandle = Output();
 
 printf(&quot;Exec Version is %d.%d\n&quot;,SysBase->LibNode.lib_Version,SysBase->LibNode.lib_Revision);
 
 if (SysBase->LibNode.lib_Version<=36)
   
    {if (!(OtherProcess35 = CreateProc(&quot;OtherProcess&quot;, 0L, OtherProcessSegList, 1000L)))
      {printf (&quot;Couldn't find OtherProcess35\n&quot;);
      exit(0);}
    printf (&quot;Loaded OtherProcess35\n&quot;);
    }
 
 /* else Kickstart is >=v36, add OtherProcess using CreateNewProc */
 else
 {
   struct TagItem TagsforCrtNewPr[5];
   
   /*open utility library*/
   if (!(UtilityBase = OpenLibrary (&quot;utility.library&quot;,0L)))
     {printf (&quot;Couldn't open utility.library\n&quot;);
      exit(0);}
     
   TagsforCrtNewPr[0].ti_Tag = NP_Seglist;
   TagsforCrtNewPr[0].ti_Data = OtherProcessSegList;
   TagsforCrtNewPr[1].ti_Tag = NP_Name;
   TagsforCrtNewPr[1].ti_Data = (ULONG)&quot;OtherProcess&quot;;
   TagsforCrtNewPr[2].ti_Tag = NP_Cli;
   TagsforCrtNewPr[2].ti_Data = TRUE;
   TagsforCrtNewPr[3].ti_Tag = NP_Output;
   TagsforCrtNewPr[3].ti_Data = MainTaskOutputHandle;
   TagsforCrtNewPr[4].ti_Tag = TAG_DONE;
   if (!(OtherProcess = CreateNewProc (TagsforCrtNewPr)))
      {printf(&quot;Couldn't find OtherProcess\n&quot;);
      exit(0);}
   printf(&quot;Other Process Loaded Successfully\n&quot;);
 }

 /*Locate MainTask*/
 MainTask = FindTask(NULL);
 Message_to_OtherProcess->MainTask = MainTask;
 
 
 /******************** WAIT FOR OTHER PROCESS TO SET UP IT'S PORT*************************/
 Delay (250);
 
 /*Send message to OtherProcess and wait for reply*/
 
 if (!(OtherProcessPort = FindPort (&quot;OtherProcessPort&quot;)))
   {printf(&quot;Couldn't find OtherProcessPort\n&quot;);
    exit (0);}
 PutMsg (OtherProcessPort, (struct Message *)Message_to_OtherProcess);
 WaitPort (ReplyPort);
 if (!(OtherProcessResponse = (struct Message_to_OtherProcess *)GetMsg (ReplyPort)))
   {printf (&quot;No message at port\n&quot;);
    exit (0);}
 
 printf (&quot;Message from OtherProcess received dude!!!\n&quot;);
 OtherProcess = OtherProcessResponse->OtherProcess;
 
 
/*void CleanUp (void)*/

/* Should have something like that ;) */


exit (0);
}




OtherProcess

Code: [Select]
#include
#include
#include
#include

#include
#include
#include
#include
#include
#include

struct Task *MainTask;
struct Task *OtherProcess; /*This one actually*/

struct MsgPort *OtherProcessPort;

struct Message_to_OtherProcess {
struct Message MesstoOP;
struct Task *MainTask;
struct Task *OtherProcess;
};
struct Message_to_OtherProcess *ReceivedMessage;

int main (int argc, char **argv)
{
 printf("OtherProcess Ver1.0, 2004\n");

 if (!(OtherProcessPort = CreatePort ("OtherProcessPort", 0)))
   {printf ("Couldn't create OtherProcessPort\n");
    exit (0);}
 
 WaitPort (OtherProcessPort);
 if (!(ReceivedMessage = (struct Message_to_OtherProcess *)GetMsg (OtherProcessPort)))
   {printf ("No message received");
    Delay (200UL);
    exit (0);}
 printf ("Message from MainTask received DUDE!!\n");
 MainTask  = ReceivedMessage->MainTask;
 
 
 OtherProcess = FindTask(NULL);
 ReceivedMessage->OtherProcess = OtherProcess;
 
 ReplyMsg ((struct Message *)ReceivedMessage);


 printf ("Message replyed...");

exit (0);
}



And by the way, could someone write a very short idiot's guide to linking with SAS C? I have it complaining about some undefined symbols and I'm pretty sure that the stub it prompts to link with as default could be the cause of some programs crashing (not in the exaple above) :oops:
\\"We made Amiga, they {bleep}ed it up\\"
 

Offline Sidewinder

  • Full Member
  • ***
  • Join Date: Mar 2002
  • Posts: 241
    • Show only replies by Sidewinder
    • http://www.liquido2.com
What is the undefined symbol that the linker complains about?

Usually the easiest way to link is to add "link" to the sc command:

sc myprog.c myprog link
Sidewinder
 

Offline Cymric

  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 1031
    • Show only replies by Cymric
Okay, this *has* been a long time for me, so please pay very close attention to what I say---it could be horrendously wrong. I am quite sure Piru and Karlos will find the bugs with their eyes shut, but I can't resist trying my hand at it.

First of all: your code is subject to deadlocks. Yes, I know you incorporated Delay()s to introduce 'sufficient' pause for the ports to appear. But that is a Bad Idea in general. Way better is to start the main program, have it start the second while waiting for a signal from the second program to start the message exchange. That way deadlocks are avoided.

Second, an illegal copy of the RKRF: Libraries informs me you need to set the Message's type and length prior to sending, which you have not done. You need to add the following lines below

Message_to_OtherProcess->MesstoOP.mn_ReplyPort = ReplyPort;

Message_to_OtherProcess->MesstoOP.mn_Node.ln_Type = NT_MESSAGE;
Message_to_OtherProcess->MesstoOP.mn_Length=sizeof(struct Message_to_OtherProcess));


Third, starting a program from the Workbench involves waiting for the startup message from the Workbench itself. I think the startup code already handles that, and it is also exceedingly unlikely that your code interferes with this special message as the message ports are very different. Nevertheless, I've always paid extra good care when dealing with the Workbench :-).

Finally, I have to admit I found it extremely odd that the return type of CreateProc() is struct Message *. Are you *sure* that it isn't struct Process *?

I hope this helps, and if not, well, I'm sure a Guru will be along shortly :-D.
Some people say that cats are sneaky, evil and cruel. True, and they have many other fine qualities as well.
 

Offline JoseTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2871
    • Show only replies by Jose
@Sidewinder

" What is the undefined symbol that the linker complains about?"
Some functions on jpeg.library. It's because I'm not giving the right instructions to compile and link I think.

"Usually the easiest way to link is to add "link" to the sc command:
sc myprog.c myprog link"

I'm using a SASC project thingie. I'll try that. After link comes the object to link with right?


\\"We made Amiga, they {bleep}ed it up\\"
 

Offline JoseTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2871
    • Show only replies by Jose
@Cymric

"First of all: your code is subject to deadlocks. Yes, I know you incorporated Delay()s to introduce 'sufficient' pause for the ports to appear. But that is a Bad Idea in general. Way better is to start the main program, have it start the second while waiting for a signal from the second program to start the message exchange. That way deadlocks are avoided."

Yes, but the stupid thing is, I'm trying to send a message with a pointer to the main task and it's allocated signal to the child process in the first place  :-) This is because the child process is loaded from disk as a separate compiled program. But I think 250 ticks (5 seconds) should be enouph as I don't have anything else running.
This is just to understand what's wrong with this and learn, I guess I'll have to get another method if I want to do this with 1.3.

"Second, an illegal copy of the RKRF: Libraries informs me you need to set the Message's type and length prior to sending, which you have not done. You need to add the following lines below
Message_to_OtherProcess->MesstoOP.mn_ReplyPort = ReplyPort;
Message_to_OtherProcess->MesstoOP.mn_Node.ln_Type = NT_MESSAGE;
Message_to_OtherProcess->MesstoOP.mn_Length=sizeof(struct Message_to_OtherProcess));"

Yes! I forgot that. Done now, but it still hangs. The child process doesn't even display the initial message on the Shell.


"Third, starting a program from the Workbench involves waiting for the startup message from the Workbench itself. I think the startup code already handles that, and it is also exceedingly unlikely that your code interferes with this special message as the message ports are very different. Nevertheless, I've always paid extra good care when dealing with the Workbench ."

Hmm, ok later:-)

"Finally, I have to admit I found it extremely odd that the return type of CreateProc() is struct Message *. Are you *sure* that it isn't struct Process *?"
It's struct MsgPort actually...

Funny that  the initialization of a program can be much bigger and troublesome than the program itself.
 
\\"We made Amiga, they {bleep}ed it up\\"
 

Offline Sidewinder

  • Full Member
  • ***
  • Join Date: Mar 2002
  • Posts: 241
    • Show only replies by Sidewinder
    • http://www.liquido2.com
Just add your object files in the command:

sc myprog.c code1.o code2.o link

or you can use slink with the object files:

slink myprog.o code1.o code2.o to myprog

will link and create the executable "myprog".
Sidewinder
 

Offline Cymric

  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 1031
    • Show only replies by Cymric
Well, waiting for a signal or message at the beginning of your main program isn't hard. Just create a named message port, have the child task find it using FindPort() and send a message to it. But that is in principle the same thing what you are trying to do here, with the exception it doesn't work ;-). (ALternatively, you can allocate a signal in the user-space range by number, say 16, and use that exclusively as a means of signalling other programs to they are ready to run. Only problem is that you have to use Wait() instead of WaitPort(), and find out the MessagePort's own signal number.)

So after inserting my code it still doesn't work. Dang. There are a few other suggestions I can help you with:
a) printf() is buffered, meaning that what you printf() is not always immediately displayed on-screen. If your program hangs before the buffer is emptied, you can wait until doomsday before you see the pent-up messages appear. So my first suggestion would be to put a fflush(stdout); after each printf() and then see where the program ends up.
b) That CreateProc()/CreateNewProc()-business is needless extra complication at this moment. Can you rewrite the programs in such a way that you have to start them both by hand and see what happens during the message exchange? If *that* is working okay, you know the error is elsewhere.

Good luck!
Some people say that cats are sneaky, evil and cruel. True, and they have many other fine qualities as well.
 

Offline JoseTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2871
    • Show only replies by Jose
@Cymric

I stripped down the CreateProc() and CreateNewProc() stuff (see below) and it works flawlessly  :-D So the problem is there.

That flush thing you mentioned I didn't do it because like it is now the OtherProcess simply outputs in it's own window.
Don't have time now, will try to output to the MainTask window later...

So, the hunt to the bug is declared  :-) What was wrong with the first versions ?


Here's the now working versions without CreateProc() and CreateNewProc():

MainTask

Code: [Select]

#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <exec/execbase.h>
#include <exec/types.h>
#include <exec/ports.h>
#include <exec/exec.h>
#include <utility/utility.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>
#include <stdio.h>
#include <stdlib.h>


struct MsgPort *ReplyPort;

struct Message_to_OtherProcess
  { struct Message MesstoOP;
    struct Task *MainTask;
    struct Task *OtherProcess;
  };

struct Message_to_OtherProcess *Message_to_OtherProcess, *OtherProcessResponse;

struct Task *MainTask; /*This task*/
struct Task *OtherProcess;



int main (int argc, char **argv)
{                
 
 BPTR MainTaskOutputHandle;
 
 if (!(Message_to_OtherProcess  = (struct Message_to_OtherProcess *)AllocMem (sizeof(Message_to_OtherProcess),MEMF_PUBLIC|MEMF_CLEAR)))
   {printf (&quot;Couldn't allocate memory for Message to OtherProcess\n&quot;);
    exit (0);}
 
 if (!(ReplyPort =  CreatePort (0,0)))
   {printf (&quot;Couldn't create ReplyPort\n&quot;);
    exit (0);}
 Message_to_OtherProcess->MesstoOP.mn_ReplyPort = ReplyPort;
 Message_to_OtherProcess->MesstoOP.mn_Length = sizeof(struct Message_to_OtherProcess);
 Message_to_OtherProcess->MesstoOP.mn_Node.ln_Type = NT_MESSAGE;
   
 
 MainTaskOutputHandle = Output();

 /*Locate MainTask*/
 MainTask = FindTask(NULL);
 Message_to_OtherProcess->MainTask = MainTask;
 
 
 /******************** WAIT FOR OTHER PROCESS TO SET UP IT'S PORT*************************/
 Delay (250);
 
 /*Send message to OtherProcess and wait for reply*/
 
 if (!(OtherProcessPort = FindPort (&quot;OtherProcessPort&quot;)))
   {printf(&quot;Couldn't find OtherProcessPort\n&quot;);
    exit (0);}
 PutMsg (OtherProcessPort, (struct Message *)Message_to_OtherProcess);
 WaitPort (ReplyPort);
 if (!(OtherProcessResponse = (struct Message_to_OtherProcess *)GetMsg (ReplyPort)))
   {printf (&quot;No message at port\n&quot;);
    exit (0);}
 
 printf (&quot;Message from OtherProcess received dude!!!\n&quot;);
 OtherProcess = OtherProcessResponse->OtherProcess;
 
 
/*void CleanUp (void)*/

/* Should have something like that ;) */


exit (0);
}



OtherProcess

Code: [Select]
#include
#include
#include
#include

#include
#include
#include
#include
#include
#include

struct Task *MainTask;
struct Task *OtherProcess; /*This one actually*/

struct MsgPort *OtherProcessPort;

struct Message_to_OtherProcess {
struct Message MesstoOP;
struct Task *MainTask;
struct Task *OtherProcess;
};
struct Message_to_OtherProcess *ReceivedMessage;

int main (int argc, char **argv)
{
 printf("OtherProcess Ver1.0, 2004\n");

 if (!(OtherProcessPort = CreatePort ("OtherProcessPort", 0)))
   {printf ("Couldn't create OtherProcessPort\n");
    exit (0);}
 
 WaitPort (OtherProcessPort);
 if (!(ReceivedMessage = (struct Message_to_OtherProcess *)GetMsg (OtherProcessPort)))
   {printf ("No message received");
    Delay (200UL);
    exit (0);}
 printf ("Message from MainTask received DUDE!!\n");
 MainTask  = ReceivedMessage->MainTask;
 
 
 OtherProcess = FindTask(NULL);
 ReceivedMessage->OtherProcess = OtherProcess;
 
 ReplyMsg ((struct Message *)ReceivedMessage);


 printf ("Message replyed...");

exit (0);
}
 
\\"We made Amiga, they {bleep}ed it up\\"
 

Offline JoseTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2871
    • Show only replies by Jose
@Sidewinder
Cool.
What about when you want to link with and external link library?
\\"We made Amiga, they {bleep}ed it up\\"
 

Offline Cymric

  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 1031
    • Show only replies by Cymric
Glad to hear that at least the messaging was doing okay now. I've dug into some forgotten Google links, hoping to find a PDF of the Guru Book, but alas, I was stuck with the criminally bad AmigaDOS manual plus some header files. Fortunately, I managed to find something which is definitely suspicious. dos/dostags.h mentions that the tags NP_CloseInput, NP_CloseOutput and NP_CloseError are all TRUE by default, meaning that the system automagically closes any open file handles for these streams upon the exit of the process. You use default input and error file handles (i.e., Open("NIL:")-sorta things), but supply the output handle of the main task. So here's what happens: the child process ends, the system closes all streams, including the output stream of the main process, thus yanking the carpet out from under the feet of your main process. It still needed that stream. So what I'm thinking is that your code actually works, but that the programs never have a chance to tell you.

To remedy this bug, either have the child process use its own output stream, or supply an additional tag to the TagList setting NP_CloseOutput to FALSE. You understand I'm kinda curious what will happen now ;-).
Some people say that cats are sneaky, evil and cruel. True, and they have many other fine qualities as well.
 

Offline Sidewinder

  • Full Member
  • ***
  • Join Date: Mar 2002
  • Posts: 241
    • Show only replies by Sidewinder
    • http://www.liquido2.com
To link with and external library just add the library name in with the object modules:

slink myprog.o module1.o module2.o mylibrary.lib to myprogram

or from sc:

sc myprog.c mylibrary.lib link
Sidewinder
 

Offline JoseTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2871
    • Show only replies by Jose
Ok, I'm back... Tried it with that NP_CloseOutput tag written as FALSE. It's better, now sometimes it crashes when I load it first time, others it works well and the OtherProcess now outputs well to the MainTask window :-)
One of the problems could be that I donn't have any cleanup deleting the MsgPorts so when I run it second time the port list is corrupt.
But still that doesn't justify the fact it randomly crashes even when run first time after a cold boot.
I remember in the RKM Lib they say that one should do a Forbid()before calling the FindPort(), but in this case I know the port is not going anywhere...
\\"We made Amiga, they {bleep}ed it up\\"
 

Offline Cymric

  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 1031
    • Show only replies by Cymric
You're not making this easy for me, are you? I'm afraid I'm at the end of my Latin, since I don't have an Amiga myself to try out your code. If this were Linux, things would be a cinch: the program dumps core, and then gdb can analyse the core quicker than a politician can change his opinion. I can only write down the following hints:

a) Try to write a program which includes the CreateNewProc()-stuff, but not the message passing. The simplest way is to comment out relevant sections with #if 0 / #endif pairs.
b) Do try the printf()/fflush() method. In addition, have the program print various values of variables, like pointers. See if they make sense.
c) Run the program through a debugger. If you use SAS/C, you can compile the program with debugging information so you don't have to stare at pure assembly. It's difficult since you're creating a separate process, and I'm fairly sure SAS/C can't debug that from within the first program.
d) Can you determine the Guru-number?

Good luck!
Some people say that cats are sneaky, evil and cruel. True, and they have many other fine qualities as well.
 

Offline JoseTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2871
    • Show only replies by Jose
Hey 8-) Went straight to c) and SAS/C does allow debbuging for subtasks and processes but I haven't read the manual in that part. Over 100 pages just for the debugger. Very complete package.

Anyway, done a step by step trace through each function and it crashes right when I call the CreateNewProc function so the problem is there, I just can't see what it is. Could it be the NP_Cli Tag ? I don't have the DOS manual... The includes say that tag is for creating a cli structure.

I'm gonna go the lazy way and wait for someone to give a hint, already tired, I'm sure I won't forget the error when I know what it is
 :-o
\\"We made Amiga, they {bleep}ed it up\\"
 

Offline JoseTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2871
    • Show only replies by Jose
\\"We made Amiga, they {bleep}ed it up\\"