Amiga.org
Operating System Specific Discussions => Amiga OS => Amiga OS -- Development => Topic started by: Jose on August 19, 2007, 12:56:26 PM
-
Hi. I've shrinked a bug to the tiny piece of code bellow. Works well when compiled with VBCC but crashes on my bare A1200 with SASC ?!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <utility/tagitem.h>
#include <exec/ports.h>
#include <dos/dos.h>
#include <dos/dostags.h>
/* Protos */
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>
void CllFnc(void);
int main (int argc, char **argv)
{ struct Process *Proc;
struct TagItem PrcTgs[5];
PrcTgs[0].ti_Tag = NP_Entry;
PrcTgs[0].ti_Data = (ULONG)CllFnc;
PrcTgs[1].ti_Tag = NP_Name;
PrcTgs[1].ti_Data = (ULONG)"TestProcessName";
PrcTgs[2].ti_Tag = NP_Output;
PrcTgs[2].ti_Data = Output();
PrcTgs[3].ti_Tag = NP_CloseOutput;
PrcTgs[3].ti_Data = FALSE;
PrcTgs[4].ti_Tag = TAG_DONE;
if (!(Proc = CreateNewProc(PrcTgs)))
printf("Thread creation error!!!\n");
else
printf("Thread creation successfull\n");
Delay(200); /* Wait 4 seconds. Normally a WaitPort or Wait should be used, */
exit(0); /* but this is just a shrinked piece of code to reproduce the bug */
}
/* Function caller */
void CllFnc(void)
{ Forbid();
printf("Test text working!!!\n");
}
-
Your bug: stdio is not thread safe.
-
You can't do a printf() inside of a Forbid();
and where is the Permit()?
-
@ChaosLord
printf() works inside Forbid() just fine (tho it is bad style IMO). Forbid() is broken when needed.
Permit() is not needed at the end of a subprocess. In fact, it's often useful to avoid the parent being allowed to run before the subprocess has terminated.
The real problem is that stdio is not thread safe.
-
Can a regular Process with no children or parents, do a Forbid() without Permit() near the end?
For example a CLI command?
-
@ChaosLord
Can a regular Process with no children or parents, do a Forbid() without Permit() near the end?
For example a CLI command?
No.
Well it can, but that is a bug (the CLI will then inherit the pending Forbid, and it will cause all sorts of nasty things).
-
Permit() is not needed at the end of a subprocess. In fact, it's often useful to avoid the parent being allowed to run before the subprocess has terminated.
If you are lucky enough not to be screwed by the process cleanup routines if the they do something which calls Wait() and breaks Forbid() state.
-
If you are lucky enough not to be screwed by the process cleanup routines if the they do something which calls Wait() and breaks Forbid() state.
Since old Workbench program must end with Forbid() + ReplyMsg() pair it is not very likely...
-
@Georg
If you are lucky enough not to be screwed by the process cleanup routines if the they do something which calls Wait() and breaks Forbid() state.
Screwed how? The execution is inside the OS now, and will not return to the seglist, so the seglist can disappear as soon as the final 'rts' has executed.
The Forbid() is there only to ensure that the final couple of instructions (typically poking some flag or calling ReplyMsg()) can execute without the seglist being unloaded under it.
-
@Jose:
Doesn't SASC use small data model by default ? Then your CllFnc has to be declared with __saveds, so that the base register (A4) is set correctly. May also be __geta4 or something, depends on the compiler.
Bye,
Thomas
-
@Thomas
Good point. That is the reason for outright crash.
However, even with __saveds it won't be safe... Neither SAS/C stdio, nor dos.library buffered I/O is thread safe.
-
Piru wrote:
Screwed how? The execution is inside the OS now, and will not return to the seglist, so the seglist can disappear as soon as the final 'rts' has executed.
Ah, yes, you're right. I used to know this things. Will do a self diagnosis and increase my lameness level.
-
Is stdio "Resident safe"?
If my cli command uses only local variables and stdio and someone makes it resident then runs the command multiple times simultaneously will it blow up because of stdio?
-
Is stdio "Resident safe"?
By default it isn't.
How to create a residentable (or pure) application depends on the compiler. For example one SAS/C you link against LIB:cres.o. With gcc you use -resident switch (should work with ixemul at least). I'm not familiar with VBCC.
This applies to c-library stdio. If you use dos.library stuff and keep all variables local then these restrictions do not apply, obviously. That way it's possible to do pure applications even without any startup or stdlib code, for example.
-
It must be what Thomas suggested, I just moved this piece of code from VBCC to SASC to be able to use it's debugger and kept most of the default options.
As for stdio not being thread safe. I've debugged various multithreaded functions in the past and worst result I've had AFAIremember was the text output being mixed up, but no crashes.
Cheers for the replies
-
@Jose
As for stdio not being thread safe. I've debugged various multithreaded functions in the past and worst result I've had AFAIremember was the text output being mixed up, but no crashes.
It can crash, it's just not very likely to happen.
However, in my personal opinion nothing is more annoying than rare, untrackable crashes.
-
Hello,
Try with this code, it certainly work better.
/* Function caller */
void CllFnc(void)
{ Forbid();
FPrintf(Output(),"Test text working!!!\n");
}
-
Try with this code, it certainly work better.
Actually it doesn't. dos.library buffered I/O isn't thread safe (that is, you cannot safely access buffered filehandle from multiple processes). The filehandle buffer isn't protected against simultanous access, so if you're unlucky things can go badly wrong.
If you print just couple of lines it's not very likely to break, however.
-
void CllFnc(void);
PrcTgs[0].ti_Tag = NP_Entry;
My Opinion:
Are we influenced by awkward Unix naming convention perhaps ? :roll:
Nowadays I see other operating systems with clear, fully descriptive, and rationally named APIs, something Amiga should've done long ago, why do certain amiga programmers insist on going the unix convetion way ?
Why not just..
void CallFunction( void );
..
newProcessTags[ 0 ].ti_Tag = NP_Entry;
..?
Just to expand, things like:
window->RPort vs screen->RastPort
struct RastPort vs struct RasInfo (without a "t")
struct RasInfo vs struct Layer_Info (with an underscore)
:-?
And these are just a few of the annoyances.
Just my opinion, no more rants lol.
-
@Einstein
Never messed with it, but I think names are irrelevant...
-
I agree, they are irrelevant when used privately, but in case of Open Source, or as formal APIs, unix like naming can be a real pain in the ass, float myCents = 0.000001;.