[Newbie] Hello... I am lost.

This forum is for general developer support questions.
Post Reply
tiffers
Posts: 8
Joined: Thu Nov 01, 2018 7:17 am
Location: Perth, Western Australia
Contact:

[Newbie] Hello... I am lost.

Post by tiffers »

Hi All,

So I've wanted to get into development for AmigaOS since I did the retro kick in 2007 or so. The retro kick is gone now, and I want to focus on developing for PPC OS4.x. I have my eye on a project on the OpenAmiga.org site, but I'm nowhere near competent enough to even volunteer yet. I've studied Comp Sci at Uni for 2 years, and learned Pascal, C, C++ and Java during that time. I learned some data structures and algorithm complexity analysis etc, so have a decent grasp on pointers and objects and OO programming etc. I haven't progressed past this, and it's been a LONG time since I was doing ANY of it, so I'm also firing up some old neuron paths to get back up to speed with programming in C. C is where I want to be.

I cannot afford a NG AmigaOne system at this time, but since WinUAE is now able to emulate PPC Classic environment successfully, I took the plunge and bought myself a copy of AmigaOS 4.1 FE and set up a development environment with SDK.

I've made a few simple programs which work well, but are probably wrong (creating a linked list but not destroying it at program end - potential memory leak I'm guessing), but it's a start.

My first project involves a simple GUI application to get the hang of how to open libraries and setup windows/gadgets etc and refresh the same as the program runs. And here is where the problem begins.

Trying to sift through all of the out of date and wrong (obsolete/deprecated/just plain bad) coding examples for 68k and PPC, the RKRMs (Exec, Devices, Libraries), the AmigaOS Wiki, OS4Coding.net, Jim Tubbs Reaction guide and more, I'm really struggling to get a cohesive understanding in my mind about how to do things, and do them correctly. I haven't looked at source code, because I don't want to pick something that's wrong, and I likely will because I don't know it's wrong.

I'm willing to do all of this footwork, because it really is enlightening, and I've learned a lot so far, but I keep hitting dead ends, and I don't even know how to look for the answer. There are enough posts saying "don't do this anymore, do this" but the code snippets aren't comprehensive for me to understand how to get to the place to do the wrong or right thing.

The questions I have right now, and I'm sure there'll be many more once I work them out are:

1) Automatically linked libraries and the use of Interfaces

There is an old way (Exec functions) and new way to (Exec Interface calling functions) open libraries using Interfaces. Many examples have IExec->OpenLibrary(...). Where does IExec come from? I seem to recall while reading through the SAS/C 6.5x docos (originally started working on a 2.05 environment - Hence SAS/C) that there is an amiga.lib which is automatically linked, or should be linked everytime if you don't rely on SAS/C to handle the linking for you. I found a reference in the AmigaOS wiki that the amiga.lib and debug.lib are "obsolete". I've tried to search for info regarding gcc and OS4.x and automatically linked libraries, but haven't succeeded yet (other than finding that -lauto and -lraauto are incomplete solutions, and possibly link libraries you will never use, and should now be avoided.)

There's a page on creating a custom library on AmigaOS Wiki that says IExec isn't automatically present in libraries like it is in a normal program, and shows how to 'open' it.

So, where _is_ IExec coming from? Is it automatic? Is this deprecated behaviour which should be avoided? Are there any other 'automatic' includes/linked libraries I should be aware of? Is there a decent place to find such information? If I were to use the IExec setup in custom library page, for a normal program would that be acceptable, redundant, undesirable?

2) How does Wait() work? The examples say effectively 'your program halts execution and waits for a signal from Intuition, when the user presses a button or something, you handle it with your code' and they make a simple example which for eg makes a window and Waits() for a close gadget and they handle JUST that gadget, close everything up and quit. They are describing Wait() from the system's perspective. The examples don't do anything beyond Intuition signalling specific things, and so I don't know how _my_ program fits in with that.

My guess, and please correct me if I'm wrong, is that Wait() halts the execution, hands the system back to Exec and then in 1/10 second (or something) Exec wakes the program back up. If there's no user interaction, the program is still woken, given NULL flags, the program can do what it needs (the actual purpose of the program) and then it loops back to Wait() for another 1/10 second. Of course if it gets signals, it also has to handle those during it's run loop. Does this sound accurate?

I'd like an in-depth explanation of how Wait() works, from the point of view of my program, not from the point of view of the system.

So there it is, the current and beginning questions from an Amiga developer newbie.

I have had some issues with the WinUAE setup, so if anyone wants to help out there, I'd be grateful. A classic example is running Codebench, when I compile my crappy code using Codebench functionality, and gcc returns errors, Codebench returns to the editor screen and crashes the system. Many things seem to crash the system. I'm stuck using Notepad and command-line gcc commands for now, but I'm ok with that (for now :-) )

Many thanks,

tiffers
User avatar
thomasrapp
Posts: 310
Joined: Sat Jun 18, 2011 11:22 pm

Re: [Newbie] Hello... I am lost.

Post by thomasrapp »

Where does IExec come from?
If you run without startup code, the system provides IExec to you. Alternatively you can read ExecBase from address 4 like in the old days and read IExec from ExecBase.

If you run with startup code, you don't need to care. The startup code provides an external symbol IExec which you can just use. You only have to declare that symbol in your program. And you don't even need to do it yourself, you just #include <proto/exec.h> and the symbol is declared in this header file.

The same is true for IDOS. The startup code opens dos.library, obtains the interface and stores it in an external symbol called IDOS.


How does Wait() work?
You assumtion is wrong. Wait() will ultimately stop your program. It does not wake up by its own. If you somehow run into a Wait(0) (i.e. wait for no signals), then your program is dead. It will never come into live again.

If you need to regularly wake up, you have to program a timer of some kind and combine the timer signal with your window signal. Or use IDCMP_INTUITICKS which wakes your window every 1/10 second, but only while the window is the active one.

If you don't want to go asleep, don't call Wait(). But also DO NOT DO BUSY LOOPS! If your processing is done, go to Wait() for user input. Whenever you need to wait for something use Wait().
Last edited by thomasrapp on Sat Nov 24, 2018 11:06 am, edited 1 time in total.
tiffers
Posts: 8
Joined: Thu Nov 01, 2018 7:17 am
Location: Perth, Western Australia
Contact:

Re: [Newbie] Hello... I am lost.

Post by tiffers »

thomasrapp wrote:
Where does IExec come from?
If you run without startup code, the system provides IExec to you.
Thanks. I found this in the AmigaOS Wiki moments ago:
Except where noted, each example was linked with the standard newlib startup code which provides the following interfaces: IExec, IDOS and IUtility
So, linking in newlib is running with startup code? Could you give some understanding why one would NOT use startup code? And I guess I should ask the newbie question, what is startup code, is there somewhere I could read about it? (is http://wiki.amigaos.net/wiki/Newlib_Library sufficient? Oooh, found this http://wiki.amigaos.net/wiki/Program_Startup too.)

Ok, I did a search and learned more :-) https://www.e-reading.club/chapter.php/ ... 2B%2B.html and http://www.bravegnu.org/gnu-eprog/c-startup.html Pretty sure this is much lower level than I am looking for, but it's good to know. Newlib includes startup code. Link with Newlib and #include <protos/exec.h> is all I need to know.
How does Wait() work?
You assumtion is wrong. Wait() will ultimately stop your program. It does not wake up by its own. If you somehow run into a Wait(0) (i.e. wait for no signals), then your program is dead. It will never come into live again.

If you need to regularly wake up, you have to program a timer of some kind and combine the timer signal with your window signal. Or use IDCMP_INTUITICKS which wakes your window every 1/10 second, but only while the window is the active one.
So, window signals 'arrive' autonomously on the 'message port' without needing to actively retrieve them? I just have to check/poll the port in my program's loop, and act accordingly?
Last edited by tiffers on Sat Nov 24, 2018 10:59 am, edited 3 times in total.
tiffers
Posts: 8
Joined: Thu Nov 01, 2018 7:17 am
Location: Perth, Western Australia
Contact:

Re: [Newbie] Hello... I am lost.

Post by tiffers »

Another question I have on my mind is that of windows, and when to open/create them.

I'm 'porting' an application fron MS Windows for which I have the Delphi source (I'm reading that code, and completely writing my own C code, in order to learn how to write Amiga C code). The program has about 4 windows, only one of which is ever seen at any given time.

In the Delphi code, using templates, the four 'forms' are setup, and then activation of the current window (based on the form) occurs when needed.

Can I open 4 windows, all with the hidden tag set, and then unhide the relevant window at the time? Should I even do this, or should I handle window opening and closing as execution jumps around in the program?
User avatar
broadblues
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 600
Joined: Sat Jun 18, 2011 2:40 am
Location: Portsmouth, UK
Contact:

Re: [Newbie] Hello... I am lost.

Post by broadblues »

Could you give some understanding why one would NOT use startup code?
For general application you would nearly always link in the C Library (either newlib or clib2 [use nwelib by default]) . You would build without startup code if writing a shared library, or perhaps a program plugin.
So, window signals 'arrive' autonomously on the 'message port' without needing to actively retrieve them? I just have to check/poll the port in my program's loop, and act accordingly?
In your Wait() loop you would add the signal flag of the windows UserPort to the mask you pass to Wait() then call Wait(signalmask) and test for the window signal in the result. If present then process the windows events. I'd receommend using a window.class window, then you don;t have to worry about replying messages and such the WM_HANDLEINPUT method does that all for you.
Can I open 4 windows, all with the hidden tag set, and then unhide the relevant window at the time? Should I even do this, or should I handle window opening and closing as execution jumps around in the program?
I theory yes you could open hidden windows, but I would not do that without a very good reason. Go for opening each window as the prgram requires them. Also if any of your windows are requesters, ie they ask a yes no question or for a filename etc with no other functionality then consider using Requester Class objects for those, or ASL for the more complex requesters like file / font requesters.

There is some example code on GUIs here http://wiki.amigaos.net/wiki/AmiWest_Lesson_4 (in a linked archive)

also here:

http://wiki.amigaos.net/wiki/Programmin ... t_ReAction
User avatar
broadblues
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 600
Joined: Sat Jun 18, 2011 2:40 am
Location: Portsmouth, UK
Contact:

Re: [Newbie] Hello... I am lost.

Post by broadblues »

You have I hope found the example code in SDK:Examples/GUI and SDK:Examples/Reaction ?
tiffers
Posts: 8
Joined: Thu Nov 01, 2018 7:17 am
Location: Perth, Western Australia
Contact:

Re: [Newbie] Hello... I am lost.

Post by tiffers »

broadblues wrote:You have I hope found the example code in SDK:Examples/GUI and SDK:Examples/Reaction ?
I have now. :-) Well, GUI.. there's no ReAction drawer.

I see the examples use the ReAction Macros. I has been said this is not a good idea. What do you advise?
User avatar
broadblues
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 600
Joined: Sat Jun 18, 2011 2:40 am
Location: Portsmouth, UK
Contact:

Re: [Newbie] Hello... I am lost.

Post by broadblues »

tiffers wrote:
broadblues wrote:You have I hope found the example code in SDK:Examples/GUI and SDK:Examples/Reaction ?
I have now. :-) Well, GUI.. there's no ReAction drawer.
I quoted both as my SDK has evolved in place over the years and I wasn't sure if the Reaction drawer was still there or it had all moved to GUI....
I see the examples use the ReAction Macros. I has been said this is not a good idea. What do you advise?
It's somewhat a matter of taste, but I prefer not to use them, rather open the classes explicitly with IIntuition->OpenClass().

You definetly have more control when *not* using them.
User avatar
tonyw
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 1479
Joined: Wed Mar 09, 2011 1:36 pm
Location: Sydney, Australia

Re: [Newbie] Hello... I am lost.

Post by tonyw »

Hi Tiffers,

Let me just expand a bit on the Wait() process and using Signals:

In AmigaOS Exec, there is only one reason why a task can be suspended (except for a crashed task), that is, that it is waiting for a Signal. There are 32 signals available (a 32-bit unsigned integer that is the parameter to the IExec->Wait(signals) call). If your (suspended, Waiting) task receives any of the specified Signals, it will be allowed to run again.

The low 16 signal bits are reserved for system use, and the top 16 are for user use. When you call IExec->AllocSignal(-1), one of the top 16 signal bits will be assigned for you (and marked down as "used"). You must IExec->FreeSIgnal() all the Signals you have allocated before you exit, else DOS will whinge and slap your wrist.

So, when you enter the Wait() phase, you specify the Signals you are Waiting for, eg IExec->Wait(Sig1 + Sig2 + Sig7). Here Sig1, Sig2 and Sig7 are 32-bit patterns, whereas when you AllocSignal() or FreeSignal(), they are a bit number (16-31). The "unused" Signal number is (-1), since zero is a valid bit number.

Some Exec calls (eg AllocSysObject(ASOT_PORT)) will allocate a Signal for you. You must check that the Signal is positive, ie not (-1), which would indicate that all Signals available to your task have been allocated.
Similarly, calls to timer device and similar will need a Signal each.

You then call IExec->Wait(sigs) in your main loop and wait to be continued. The return from Wait() is the pattern of Signals that allowed you to continue - check them all, as they are a "one-shot" signal and if another comes along before you have used and cleared the first one, you won't know about it. Clear each signal before you return to the Wait() state.

There is plenty of description in the Exec docs (SDK:Documentation/AutoDocs/exec.doc).
cheers
tony
Post Reply