Beginner questions (C/OSLib)
Richard Walker (2090) 431 posts |
Hi all, I’ve finally moved my Pi, updated my SD card (firmware, ROM image and HD4) and got the DDE installed. After a bit of fun with installing OSLib, I have managed to get a simple Hello World command-line program running – complete with the new-trendy shared makefiles. I’m happy with all that. I knocked up a quick program to open a USB endpoint and read some bytes. This sort-of works (the issues I have with it can wait!). It uses only the pure ANSI C functions provided in stdio.h. I wanted to investigate OSLib, so decided to change my ‘fopen’ to ‘osfind’ and ‘fread’ to ‘osgbpb’. Similar result (as you’d expect) but with one critical difference: if the OSLib version of the code crashes, or I abort it with ESCAPE, then I cannot re-run it without re-booting (I get ‘endpoint in use’ when my code tries to do the osfind again). I must have overlooked a difference! Do I need some sort of ‘cleanup’ section in my code? Is there something I can detect from the osfind failure and re-try cleanly? (I assume this is what open does behind the scenes, but I don’t know) Apologies for the beginner-ish nature of this. I have barely touched RISC OS for about 15 years (and even back then, I only used GCC or the DDE once or twice). I actually write software professionally, so the concepts are not an issue – it’s just the unfamiliarness of the specific environment. Cheers, |
Jeffrey Lee (213) 6048 posts |
On most operating systems, when an process terminates the kernel will make sure that all the resources the process was using (memory, file handles, sockets, etc.) get cleaned up correctly. RISC OS has very poor process management – a lot of the housekeeping when your process exits (or crashes) has to be done manually. For applications, the C library will take care of closing open If you’re bypassing the C library’s file management and making direct OS calls then you’ll have to make sure you close the files manually whenever your app exits. There are a couple of ways you can go about things:
Also, if you start writing modules:
|
Rick Murray (539) 13840 posts |
I believe files open with fopen() will be closed, but ones opened using RISC OS’s native calls (OS_Find) will not be closed. |
Stuart Swales (1481) 351 posts |
The C library is your friend here. If you bypass it, prepare for extra work as Jeffrey outlines! |
Rick Murray (539) 13840 posts |
Hmm, pass a stale file handle to CLib and watch the machine hang. ;-) |
Stuart Swales (1481) 351 posts |
Defensive programming is also your friend ;-) e.g. file_dispose(FILE “**”) that zeroes the FILE “*” on close…, alloc_dispose(void “**”) (albeit annoying with Norcroft) etc. Trivial wrappers that save buckets loads of heartache. |
Richard Walker (2090) 431 posts |
Ah… Thanks chaps. I thought I had a good idea at lunchtime… Look at the CLib source code and see how fopen is implemented. Funnily enough, just the same SWI calls as I am making. So I was still scratching my head! I think Jeffrey’s bit about the CLib runtime doing some cleanup must be where the solution lies. I will have a flick through the PRMs and see if I can find examples. I shall no doubt be back with more silly questions! Thanks everyone. |
Richard Walker (2090) 431 posts |
I have had another fiddle. OSLib stuff now working as I would expect – Jeffrey was right on the money, I needed an atexit handler. What is the consensus for such C programs? Do we hit the various SWIs (directly or via OSLib) or do people prefer using the ANSI libraries? Most example RISC OS code I see is all about the former. I thought I would play around with a simple command line program, then progress to a module. Should I revise that, as it seems there are greater differences at play in RISC OS? Also, my program uses printf for debugging. What is the proper way to achieve this on RISC OS? Is there a framework I should be using? Now I am going to do some reading on USB input, as it doesn’t sound straightforward! |
Jeffrey Lee (213) 6048 posts |
Depends on use case. ANSI works OK for streaming of files (i.e. reading/writing bits at a time). But if you want to read/write a file in one go then using OS_File directly is generally quicker and easier (in terms of programming effort and runtime performance). And if you care about filetypes (e.g. when writing) or have special requirements (e.g. the ANSI functions may attempt to perform their own buffering, which could cause problems with “device as a file” things like USB) then using OS SWIs is generally the only way.
Normally starting with a command line app is fine, but since USB is a bit tricky to use effectively you may encounter some issues with doing USB in an app which wouldn’t be present if you were doing it in a module. |
Ronald May (387) 407 posts |
To make life more RISC OS friendly while dealing with unix binaries from Obey files, I have decided to make a command similar to or better still, using Do (from the BootCommands module) Before xos_cli I want to add a routine to unixify any paths.<myprog$Dir> type is the normal requirement.In BASIC something like
does the job. This BASIC relied on the Variable peing passed with Do so it is already expanded. The binary should allow one to do unixdo Set MYPROGHOME <myprog$Dir> to get a unix program variable set for example. The advantage being that when the unix prog appends various filenames for logs pids etc, It is then all in unix form and doesn’t break. Unixlib /could/ handle a pure RISC OS path otherwise. The previous example could be achieved my modifying the source code, but you loose flexibility to alter the desired destination. Ramdisc might be preferrable in some instances. Probably would need to convert multiple sys variables the same way Do does with xos_gs_trans() to be complete. Anyone see any pitfalls, or perhaps feel like making a c binary? :-) |
Colin (478) 2433 posts |
It’s easy enough to do from BASIC if that is what you would prefer. If you look in the CVS download I recently announced theres a basic program in sources called convert_files which has a procedure PROCget_args which returns a string array – argv$() – and the number of arguments – argc%. Note you can put an argument in inverted commas if there is spaces in it, the inverted commas are stripped. argv$(0) is the path used to run the program, like <obey$dir>, the other entries in argv$() are the command line arguments You then just need to canonise any paths – not gstrans, I think its os fscontrol something or other. |
Colin (478) 2433 posts |
Thinking further about it do you actually need a conversion Does
work for you. It works for me with cvs which I set up like this
|
Jeffrey Lee (213) 6048 posts |
The advantage being that when the unix prog appends various Unixlib can handle pure RISC OS paths if it’s configured correctly.
Of course if you’re dealing with unix vs. RISC OS filenames on the command line, user interfaces, etc. then some extra logic in the program (or a utility like unixdo) might be necessary to make sure that the filename is in the right format before the core of the program starts to manipulate it. |
Ronald May (387) 407 posts |
Hi Jeffrey,Colin, Edit: pretty busy with house and summer is ending, but Colin, results in the usual mix of formats./ADFS::Hit75.$.Yahoo.!Fetchmail/fetchmail.pid: No such file or directory fetchmail: lock creation failed. My BASIC thingy is a bit clunky but works. Probably should have the two arguments the other way round to resemble Set closer.Regarding your suggestion to make the utility in BASIC, There is also Basalt and Steve Revills Routines for easier argument handling, but I would be missing out on Do’s established error handling, and many moons ago was told that running cli programs from BASIC is problematic. Another thing Do already has established. |
Richard Walker (2090) 431 posts |
Thanks Jeffrey, for the comments on SWI vs. ANSI. Makes sense to me. I just need to experiment with some logging (DADebug looks interesting) and get my head around USB input. I have read a few threads on here, as there seems to be a lack of official documentation, and it seems ‘unsettled’ to say the least! And as you say, I should look into modules, as my techniques may need to change. Any pointers on any of that, particularly USB, would be welcome. |
Ronald May (387) 407 posts |
Jeffrey you mentioned the sfixing etc (e.g. for GCC it will say that c, h, etc. files should appear in folders with those names)Keep in mind that there are are lot of non compiler related unix ports for people to use. However I checked what would happen with gcc as an example of a sfixing aware program, using actual directory Ram::RamDisc0.$.src.c.test (and h.test) gcc -c Ram::RamDisc0.$.src.test.c works equally to gcc -c Ram::RamDisc0.$/src/test.c The only catch would be that gcc would only work with a path variable for the srcfiles to be appended to. unixing to Using just a directory variable and gcc doesn’t have the full path for the .o fileThis example is assuming you would want to over-ride using the CSD for src. It is possible there could be a use somewhere, maybe in makefiles, particularly GNUMakefiles running utilities that may not find the CSD or other directories for some reason. |