🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.sys.amiga.tech
Article #3463

Re: Problem with CreateProc & LoadSeg

#3463
From: Christian Motz
Date: Sat, 05 May 1990 08:23
137 lines
7197 bytes
In article <897@tau.sm.luth.se> d87-khd@sm.luth.se (Karl-Gunnar Hultland) writes:
>
>I have some sort of problem with an application I'm working on.
>I want to have a main program which should take care of menues etc and
>then upon command Load and Create some new processes who will open a
>window on the Custom screen and execute in that window.
>
>The problem is :
>If I comment away the LoadSeg and CreateProc and start the program
>Proc.c via a different CLI it works Like a Dream. BUT if I use the
>code in Main.c I never get the window to open.
>I have verifyed with Xoper that the process exists but doesn't open 
>the window and thus it can't exit.
>
>The question is: Is there ANYTHING I should do that I don't??

If I judge this right from the description of  the  problem,  you  are
basically trying to run an asynchronous Process  using  LoadSeg()  and
CreateProc(). I tried this, and  after  some  time  got  it  to  work,
although I am quite sure that my method is somewhat illegal. But  more
about that later on.
   When a program is started, the C startup code checks to see whether
it is started from the CLI (or via Execute() for that matter) or  from
Workbench. This is done by checking the pr_CLI member in  the  process
structure. If it is NULL, the code assumes it has  been  started  from
Workbench and therefore is waiting for a  Workbench- startup- message.
I suppose  that  this  is   the   problem   you'  re   having --   the
main()-function never gets called although a process has been created,
right? Obviously the C startup  code  is  waiting  for  the  Workbench
message it never gets.
   The "clean" way to circumvent this, I think, is to not  use  the  C
startup code, i.e. _main(). This of course can be painful if you  like
to use stdio stuff, but it works.

Now for the "dirty" way, and  my  question  how  dirty  this  is,  and
whether or not there is any cleaner way to do it. My  problem  was  to
start a process much like Execute(), only asynchronously. As far as  I
know, AmigaDOS knows no call for something like this. I know there are
things like ArpAsyncRun(), but I would like to  do  it  on  a " stock"
Amiga (besides: I wonder if ArpAsyncRun() is so clean itself).

Now hold on to your seats, NetPeople, just in case this is  the  worst
programming practice you have ever seen -- feel free to flame me,  but
only if you know of a better, "legitimate" solution.

Code fragment follows ...



/*
** We LoadSeg() the compress code at this point if it is not already
** loaded. With this we can achieve an additional performance increase
** by LoadSeg()'ing it just once at the beginning, then reusing it over
** and over again and UnLoadSeg()'ing it when we're done. This saves
** valuable time loading the code in memory.
*/
        if (seglist == 0L) {
            seglist = LoadSeg(comp);
        }
/*
** Now it is time to open the files to be used as compress's standard
** in- and output. We have to seek to position 12 of the input file,
** since it begins with "#! cunbatch\n" before the compressed batch
** file. Standard output is, of course, the pipe. We open them here
** because it would mess with the Forbid()-call if we would do it
** later on, since I/O re-enables Multitasking, thus effectively
** voiding any setup we make for the new process.
*/
        if (seglist != 0L) {
            if ((cis = Open(in, MODE_OLDFILE)) != NULL) {
                Seek(cis, 12L, -1L);
                if ((cos = Open(pn, MODE_NEWFILE)) != NULL) {
/*
** Here comes the tricky part. We have to create the process from the
** loaded code and hand the command line arguments to it. For this we
** disable multitasking while we set up the process environment of the
** new process, to keep the operating system from messing with the data.
*/
                    Forbid();
                    pid = CreateProc("compress", 0L, seglist, 4000L);
/*
** Guess how long it took me 'til I found out that CreateProc() returns
** the address of the process's MessagePort, not its process structure?
** Anyway, the MessagePort is the second member of the structure, the
** first being the Task structure. Thus the process structure address
** is pid-sizeof(struct Task). Voila, you have the process address,
** allowing you to manipulate it any way you want to. This of course is
** an assumption, and thus bad programming practice. But what else are
** you supposed to do under this operating system?
*/
                    pr = (struct Process *)(pid - (long)sizeof(struct Task));
                    pr->pr_CIS = (BPTR)cis;
                    pr->pr_COS = (BPTR)cos;
                    cli->cli_CommandName = (long)cmd >> 2L;
                    pr->pr_CLI = (long)cli >> 2L;
/*
** Have you ever thought about how command line arguments are passed
** under AmigaDOS? No? Well, the read this and learn something :-).
** A newly created process gets the address of the command line
** parameters in the processor register A0, and its length in the
** register D0. This is all very fine and dandy, and makes for nice
** and easy startup code. But if you try to create a process and hand
** it some parameters, it is virtually impossible to set these registers
** in an operating system-friendly fashion. The only way I have found is
** by determining the addresses of these registers in the initial
** register set on the process stack, and writing to them the desired
** values. This of course is really messy and ugly, so you may not want
** to look at it.
*/
                    t = (long)(pr->pr_Task.tc_SPUpper);
                    d = t - 68L;
                    a = d + 32L;
                    a0 = (char **)a;
                    d0 = (long *)d;
                    *a0 = opt;
                    *d0 = (long)strlen(opt);
/*
** Everything is set up now, so we can allow the operating system to
** resume multitasking, thus allowing the new process to be scheduled
** for execution. We don't care what happens to it (actually we have
** no other choice), so we continue by calling unbatch, feeding it the
** pipe as input file.
*/
                    Permit();

End of code fragment ...



How long can you get thrown in jail for doing something like that? But
seriously, how about a better way? Any hint would be appreciated.  The
above code works, no doubt about it, but after writing it I felt  like
I had just emerged from a pile of  sh**,  because  of  all  the  messy
things I did and assumptions I made ...

--
Christian Motz                                     root@dialog.sub.org
Technical Details
Message-ID: <1856@dialog.sub.org>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!usc!snorkelwacker!ira.uka.de!smurf!nadia!dialog!root
References: <897@tau.sm.luth.se>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!usc!snorkelwacker!ira.uka.de!smurf!nadia!dialog!root
From: root@dialog.sub.org (Christian Motz)
Newsgroups: comp.sys.amiga.tech
Subject: Re: Problem with CreateProc & LoadSeg
Summary: Now there's a real problem with AmigaDOS
Message-ID: <1856@dialog.sub.org>
Date: 5 May 90 08:23:45 GMT
References: <897@tau.sm.luth.se>
Sender: uucp@dialog.sub.org
Reply-To: root@dialog.sub.org (Christian Motz)
Organization: Dialog Software Development
Lines: 137