Path: 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 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