Math in processes
5 messages in this thread
Many thanks to everybody who has helped me in the last couple of months.
I'm beginning to get the hang of C at last. Apologies for not replying to
all who helped.
Now can someone help me with the following program, please?
The Process_Test routine is called twice, first as a process and then as a
normal routine. When it runs as a process, it gives a different output.
Why? It seems that the IEEEDPFix routine rounds to the nearest integer
when running as a process, but truncates towards zero otherwise. The RKMs
are not specific on which of these behaviours is the correct one.
My Amiga 2000, WB3.1 has a math FPU fitted, if that makes any difference.
#include <math.h>
#include <libraries/mathieeedp.h>
#include <dos/dostags.h>
double val;
BOOL done;
void DoDigit()
{
int n;
n = IEEEDPFix( val );
printf("Character '%c', n = %d\n", '0' + n, n);
val = (val – IEEEDPFlt(n)) * 10.0;
}
__geta4 void Process_Test()
{
int i;
val = 3.1415926535898;
for (i = 0; i < 7; i++) DoDigit( val );
done = TRUE;
}
void main()
{
printf("\nRun process:\n");
CreateNewProcTags( NP_Entry, Process_Test, TAG_DONE );
done = FALSE;
while (! done ) Delay(1);
printf("\nCall directly:\n");
Process_Test();
}
Regards,
Shraddhan (via AP from Hertfordshire, England)
The math coprocessor has to be set up by your startup code. Chances are,
when you run as a process your compiler system's startup code is setting it
up correctly. When you're running as a task, your startup code probably
isn't getting executed, so you need to duplicate it yourself.
If you have SAS/C, the file SC:SOURCE/_FPINIT.C contains an autoinitializer
function which initializes the coprocessor.
Oh, there is another possibility, too – if you are using Commodore's IEEE
library, you MUST do the OpenLibrary() on the math library from the task that
is calling the library. OpenLibrary() does the chip initialization for you,
but it does it only for the task/process that executes it. It is technically
illegal for you to pass library bases between tasks/processes, and this is
one of the reasons.
–Doug
Doug,
Thanks for you comments, and apologies for the delay in replying (I've
been out of the country for some weeks.)
re: using Commodore's IEEE libraries from a task and a process, you say
that it is technically illegal to pass library bases between
tasks/processes.
In this case, I am stumped. The situation is that I have a large program
which launches a small process. This process allows the user to inspect
various data strucures in the main program. To do this, the process uses
the main program's output routines, which are very complex and which can
use the IEEE libraries. I don't want to duplicate the output routines due
to their size and complexity.
Now, everything works fine with my code except for one of the IEEE library
calls. Is the solution to somehow ensure that only one task/process can
use the output routines at any given time, and to set up the library bases
appropriate for the task/process calling these routines?
You say that it is technically illegal to pass library bases between
tasks/processes. Does this apply to other libraries as well as the IEEE
libraries?
Regards,
Shraddhan (via AP from Hertfordshire, England)
Shraddan,
although it is officially illegal to pass library pointers among different
tasks, it may work, because library code is actually called as a
subroutine of the task.
But think twice! If the library code does a Wait() (Most dos and stdio
routines do this), or uses Semaphores, the task which opened the library
may be signalled instead, causing a lockup of the child task, or worse.
This will occur if the library will do a FindTask() and performing other
initializing for each task it was opened from, caching the results in a
list for later use, and releasing it when the task closes the library.
I don't think the IEEE libraries will do something like this, so they will
most likely cause no harm when called through a 'borrowed' library base
pointer.
I rather believe your child process jumping to the I/O-routines of your
main process will cause errors, because the mp_SigTask field of every
MsgPort will most likely be set inproperely, causing the wrong task to be
signalled on a Wait().
– wkc – … via AP from Hamburg, Germany
Well, the problem with IEEEBase in particular is that tasks using it need to
preserve floating point registers when system interrupts occur, so I think
the library allocates some extra space in the library structure for them. If
your subtask and your main task both use the same instance of IEEEBase, they
may conflict with each other. Also, the IEEE library OpenLibrary() vector
sets up the math coprocessor for your task in a task-specific way. (Sorry,
I'm definately hand-waving here from memory of Mike Sinz and Randell Jesup
talking about this elsewhere.)
Why is it such a problem to call OpenLibrary() from the subtask? If the
problem is the use of externs, get my "amiproc" utility routines; these
routines duplicate the near data section of the main task for a subtask,
assuming the main task was linked with cres.o. This allows both the main
task and the subtask to have their own private copy of IEEEBase as an extern.
We have just released the V6.55 patch to SAS/C, and amiproc is included in
there in the SC:EXTRAS drawer. I also distributed it a few months ago, and
it should be around someplace on aminet.
–Doug