home *** CD-ROM | disk | FTP | other *** search
-
- A Tutorial on exec, i/o, and Multi-tasking
- (c) By John T. Draper
-
- A product of the Programmers Network, A Software Developers Guild and
- Information source for Independent programmers. Permission to distribute
- this is granted as long as the title and header is included. For more info
- on how to join the Programmers Network, Contact John Draper at the following
- net address:
-
- USNail: 310 WestLine Dr. B210
- Alameda, Calif. 94501
- (415) 769-1268
-
- UUCP: ...ihnp4!ptsfa!well!crunch
- BIX: crunch
- WELL: crunch
- DELPHI:CRUNCH
-
- THE BASICS OF EXEC
- ------------------
-
- All programs running on the Amiga are under control of the EXEC. You can
- think of the EXEC as a very fast program that controls all other programs
- running on the Amiga. Programs come in 3 flavors. Processes, Tasks,
- and Interrupts. In this tutorial, the term "Task" will mean a separate
- "Program" or set of instructions. The EXEC has the responsibility of deciding
- which TASK gets control of the CPU. Tasks can have a specific PRIORITY. The
- range of prioritys can be from -128 to +127. Normally, user programs run
- at priority 0. Intuition runs at priority 50, and programs can change their
- priority if necessary. The PRIORITY of a program determines which place in
- line it has in relation to other programs waiting for their turn to run. It's
- like "Waiting in line" to get your chance to use the CPU.
-
-
- THE EXEC CONTROLS TASKS (among other things)
- --------------------------------------------
-
- Tasks can be in 3 states: Running, Ready, and Waiting. A "Running" task
- actually has control over the CPU, It now "Owns" the CPU for a specified
- period of time called a QUANTUM. A QUANTUM is a set period of time, that
- can be changed, and is somewhere around 50 Milliseconds. After its time is
- up, the EXEC saves the state of the program on its own stack, and switches
- to the NEXT program in line. The program that just gave up the CPU gets put
- into another line. This line is the "Ready" line. If that task has a higher
- priority than the highest task in that "Ready" list, it gets shoved in the
- front of that list. When the program thats running, executes a "Wait" or
- a "WaitPort" instruction, the task in the front of the "Ready" list gets
- a chance to run again, until either its QUANTUM is up, or it executes
- a "Wait" instruction.
-
-
-
-
- LISTS OF "Things" THAT EXEC CONTROLS
- ------------------------------------
-
- Speaking of "Lists", the Amiga has a standard way of dealing with lists.
- A good description is in the first chapter of the VOL 1 RKM. A list is
- a collection of "Nodes". Just about everything in the Amiga has a Node.
- Tasks, Messages, Ports, I/O Blocks all have Nodes. This gives the
- Exec a consistant way of handling each of these. This means that Messages
- can be put into a "List" of messages, Ports can be put into "Lists" of Ports
- and so on. This permits a very flexable way for an Amiga programmer to
- control the various resources of the system. The RKM doesn't do a very
- good job in explaining what lists are used for, it just does a good job
- in explaining what they are, and how to manipulate them.
-
- A "List" structure is shown below, and how it connect up a few "Nodes".
-
- -----------> struct Node {
- | struct Node *ln_Succ; (ZERO)
- struct List { | struct Node *ln_Pred; <------
- struct Node *lh_Head; ----- UBYTE ln_Type; |
- struct Node *lh_Tail; (Always Zero) BYTE ln_Pri; |
- struct Node *lh_TailPred; ----- char *ln_Name; |
- UBYTE lh_Type; | }; |
-
- UBYTE lh_pad; (Not used) | |
- }; | struct Node { |
- | struct Node *ln_Succ; <------
- | struct Node *ln_Pred; <------
- | !! !! |
- | |
- ------> struct Node { |
- struct Node *ln_Succ; <------
- struct Node *ln_Pred; (Zero)
-
-
- JUST ABOUT EVERYTHING IS A NODE
- -------------------------------
-
- A Node is sort of a "Connection point" where the various structures can
- be connected. Usually, Nodes are connected or arranged in some sort of
- a "List". Nodes can be move from list to list. Nodes can be Tasks,
- Processes,
- Messages, Message ports, I/O Blocks, and just about anything else in the
- Amiga. Not everything is a node. For instance: Gadgets, Menus, and
- Windows are NOT nodes. I don't know why!! Perhaps RJ can comment on that.
-
- As shown above, Three Nodes are connected in a "List". If these nodes
- are Tasks, and the list happens to be a "Ready" list, these Nodes are inserted
- in such a way that the Highest priority is at the "Head" of the list.
- the Exec function Enqueue() is probably used.
-
- The "ln_Pri" field is the nodes Priority field. Because these Nodes are
- Tasks, the ln-Pri field then determines that Tasks priority. Other entities
- have Nodes, like Messages, and Ports. These also have "Priorities", or
- ln_Pri fields. If you are using the sound drivers, the ln_Pri field is used
- as a "Precidance". Sometimes, this field isn't really used by Exec. You can
- use it in your OWN Custom nodes should you decide to create your own. So,
- we now have these Lists and Nodes, what can we really do with them?
-
-
- DIDDLING WITH NODES
- -------------------
-
- We can create a New List, by calling "NewList". Unless you are an advanced
- programmer, you probably won't ever have to use this function. It is probably
- called when you Create a Port, or in some of the lower level Exec functions.
-
-
- INSERTING A NODE
- ----------------
-
- After you create this "List", now you can "Attach" nodes to it. Use the
- Insert() function. For example: Insert(Mylist, MyNode, Pred); Where:
-
- struct List *MyList; /* Is a pointer to my List structure */
- struct Node *MyNode; /* Pointer to the Node that I want to Add to the list */
- struct Node *Pred; /* Pointer to the Node in the list, where "MyNode" gets
- inserted AFTER */
-
- If Pred = 0, the node will be added at the Head of the list. If the Pred
- node points to the list lh_Tail field, it will be inserted at the "Tail" of
- the list. You can "AddHead" and "AddTail", also "Remove" a node.
-
-
- PRIORITIZED INSERTION
- ---------------------
-
- The Priority field of the Node can also be used to determine the position in
- the list where a node can be inserted. When your task finishes its turn
- using the CPU, this function is called. This is called PRIORITIZED INSERTION.
- The "Enqueue" function inserts a node into a list AFTER the last node of same
- or higher priority. For example: Enqueue(MyList, ANode); Inserts
- "ANode" into "MyList" where they are declared as:
-
- struct List *MyList; /* A pointer to the list we want to insert in */
- struct Node *ANode; /* The Node that I want to insert */
-
- Naturally, before "Enqueue" is called, the Nodes ln_Pri field is set
- as follows: ANode->ln_Pri = <some priority value>, For instance, just
- before you add a Task, you must set the tasks Priority field. If "MyTask"
- is a pointer to a task, then: MyTask->tc_Node.ln_Pri = PRIORITY; Will set
- that tasks Priority. This is usually done before your task becomes activated.
-
-
- FINDING NODE BY NAME
- --------------------
-
- Finally, each node can have a "Name" pointer "ln_Name". Using Names is
- useful for "Debugging" purposes and otherwise identification of them. A
- Function called FindName will return a pointer to the node, given a pointer
- to a null terminated string, and a list. For example:
-
- FoundNode = FindName(MyList, "MyNode"); Where MyList is a pointer to a List,
- and "MyNode" is the Name for that node. "FoundNode" is a pointer to the
- node with that name. If No name exists, function returns a NULL. To find
- multiple entrys, call function again.
-
-
- MOST EXEC STRUCTURES HAVE NODES IN THEM
- ---------------------------------------
-
- As mentioned earlier, just about every C structure contains a "Node"
- structure within it. Notice that the FIRST entry in a Task structure is
- a "Node". So, a Task node can be referenced by: tc_Node. Notice that
- this field is an "INSTANCE" of a node. This means that the Task structure
- has a Node contained within it. This ISN'T a "Pointer", it is the actual
- structure. If a field within a structure is a "POINTER", it contains an "*"
- in front of it. Part of a Task structure is listed below, Refer to Pg 1-15
- Vol 1 of RKM for entire structure.
-
- struct Task {
- struct Node tc_Node; /* Tasks Node structure */
- UBYTE tc_Flags
- !! !!
- !! !!
-
- Each NODE has a Type. Each List also has Types. There are MANY DIFFERENT
- Types. For instance, a Task Node has a type of NT_TASK. If a node is
- attached to a "Message", its type is NT_MESSAGE. For instance, we might
- have a "List" of Messages attached together for some purpose, for instance,
- messages queued up in a message port are lists of message nodes.
-
- So the "List" lh_Type field in the list would have NT_MESSAGE as its
- Type. Then each Message in that list would have to have its ln_Type field
- also set to NT_MESSAGE. In the "exec/nodes.h" header file is a definition of
- the various Types and their values. These values are from 0 (unknown) to
- 13 (a Process). You can define your OWN lists. If you do, make sure that
- you choose a number above 64. I'm sure that Amiga will be sequentially
- "assigning" various Node types for future use. I am sure that Amiga would
- want you to choose Node types that wouldn't have much of a chance of Clashing
- with future types. Some of the types are listed below:
-
- NT_TASK - A Task node.
- NT_INTERRUPT - An Interrupt node.
- NT_DEVICE - A Device.
- NT_LIBRARY - A Library
- NT_FONT - A Font
- NT_MESSAGE - A message
- NT_MSGPORT - A Message port
-
- These are to name a few. There are more, but these are the most Common
- parts of the Amiga operating system. Notice that NOTHING was mentioned about
- AmigaDOS. AmigaDOS is a separate "Layer" or set of programs that run "on top"
- of the Exec. Because of this, separately generated tasks CANNOT CALL any of
- the AmigaDOS functions. A lot of the C Library functions like "printf" must
- call the AmigaDOS functions, and CANNOT be used from within a task. They CAN
- be called from separate Processes. A Process is different than a task.
- There is a very LIGHT discussion on "Processes" in the AmigaDOS manuals
- and won't be covered here.
-
- Next time, I'm taking it further into the relationship of how all this
- is put together. Just about EVERYTHING works the same way, for instance,
- all the EXEC I/O can run as Tasks. When an IO request is made to start up
- the Narrator, the "SendIO" function is called which can "Activate" an IO
- task, then when that task gets done "Doing its thing", it sends a Message
- back to a designated "Message Port" telling the calling routine that It's
- finished. In the meantime, your program was running off doing other things
- until it recieved a "Signal" from the IO device. The Serial, Parallel,
-
- Sound, Narration, Disk Device, and ALL other devices work in EXACTLY the same
- way.
-
- Enuff for a nights work. Now if someone would hire me, and treat me
- nice, I would be able to find time to post more of these tidbits of wit.
- Adios folks, Till next time......
-
- Crunch (The Cap'n)
- Programmers Net
- On the WELL
- "Da place where us global village folks live"
-
-