home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #4
/
amigamamagazinepolishissue1998.iso
/
airi
/
executive_v2.10
/
data
/
developers.lha
/
ExecutiveAPI
/
Example.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-02-23
|
10KB
|
489 lines
/*
* ExecutiveAPI example
*
* This file is public domain.
*
* Author: Petri Nordlund <petrin@megabaud.fi>
*
* $Id: Example.c 1.1 1996/10/01 23:06:09 petrin Exp petrin $
*
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ExecutiveAPI.h"
#ifdef __SASC
#include <dos.h>
#define GETA4() geta4()
#else /* GCC */
#define GETA4() ix_geta4()
#endif
#define STACK_SIZE 10000L
void MyExit(void);
BOOL SendMessage(struct ExecutiveMessage *msg);
void WatchMe(void);
void WatchMe_entry(void);
void WatchRelative(void);
void WatchRelative_entry(void);
struct ExecutiveMessage *msg = NULL;
struct Task *parent_task;
BYTE parent_signal;
WORD active_tasks = 0;
/**
** This is an example on how to use ExecutiveAPI. All ExecutiveAPI features
** are demonstrated.
**
**/
int
main(int argc, char **argv)
{
LONG oldnice;
atexit(MyExit);
/**
** Allocate ExecutiveMessage structure and initialize it.
**
**/
if(!(msg=AllocVec(sizeof(struct ExecutiveMessage), MEMF_PUBLIC|MEMF_CLEAR)))
{
puts("Can't allocate ExecutiveMessage structure.");
exit(RETURN_FAIL);
}
if(!(msg->message.mn_ReplyPort=CreateMsgPort()))
{
puts("Can't create message port.");
exit(RETURN_FAIL);
}
msg->message.mn_Node.ln_Type = NT_MESSAGE;
msg->message.mn_Length = sizeof(struct ExecutiveMessage);
/** Make sure this is always initialized to zero! **/
msg->ident = 0;
/**
** Add this program as Executive client. Executive can't quit
** before all clients have been removed.
**
**/
msg->command = EXAPI_CMD_ADD_CLIENT;
if(!SendMessage(msg))
{
puts("Can't add new client.");
exit(RETURN_FAIL);
}
/**
** Ask Executive to return the real (not the scheduling) priority of this
** task. If this task is currently scheduled and you read the priority
** directly from task-structure, it will be somewhere in the dynamic
** range. There's no GetTaskPri() routine in exec.library which could
** be patched to return the real priority.
**
** In a case a new task is launched with its parent task's priority, which
** is in the dynamic range, Executive notices this, and sets the real
** priority of the new task to its parent task's real priority. But if
** wish to create a childtask whose priority will be the priority of the
** parent task plus one, and you read the priority from task-structure, it
** might be something like -58. Add one to this value, and you'll get -57.
** Executive can't correct this, so in this case use the
** EXAPI_CMD_GET_PRIORITY command to obtain task's real priority.
**
**/
msg->command = EXAPI_CMD_GET_PRIORITY;
msg->task = FindTask(NULL);
if(!SendMessage(msg))
{
puts("Can't obtain this task's real priority.");
exit(RETURN_FAIL);
}
printf("Scheduling priority: %d --- Real priority: %d\n",
FindTask(NULL)->tc_Node.ln_Pri,
msg->value1);
/**
** Set this task's nice-value to -10. Store old value and restore it later.
** You should restore the nice-value, if the program can be executed in a
** shell, as the shell process will then get the nice-value.
**
**/
msg->command = EXAPI_CMD_SET_NICE;
msg->task = FindTask(NULL);
msg->value1 = -10; /* new nice-value */
if(!SendMessage(msg))
{
puts("Can't set this task's nice-value.");
exit(RETURN_FAIL);
}
oldnice = msg->value1;
printf("Old nice-value: %d\n",oldnice);
/**
** Get current nice-value.
**
**/
msg->command = EXAPI_CMD_GET_NICE;
msg->task = FindTask(NULL);
if(!SendMessage(msg))
{
puts("Can't obtain this task's nice-value.");
exit(RETURN_FAIL);
}
printf("Current nice-value: %d\n",msg->value1);
/**
** Restore old nice-value.
**
**/
msg->command = EXAPI_CMD_SET_NICE;
msg->task = FindTask(NULL);
msg->value1 = oldnice;
if(!SendMessage(msg))
{
puts("Can't set this task's nice-value.");
exit(RETURN_FAIL);
}
/**
** Two EXAPI_CMD_WATCH examples.
**
**/
WatchMe();
Delay(2*50);
WatchRelative();
/**
** Client is removed in MyExit(). Don't forget to do it.
**
**/
return(RETURN_OK);
}
void
MyExit(void)
{
/**
** Remove the client. This can't fail.
**
**/
if(msg && (msg->message.mn_ReplyPort))
{
msg->command = EXAPI_CMD_REM_CLIENT;
SendMessage(msg);
}
/**
** Delete the message.
**
**/
if(msg)
{
if(msg->message.mn_ReplyPort)
DeleteMsgPort(msg->message.mn_ReplyPort);
FreeVec(msg);
}
}
/**
** Send message to Executive's public message port.
** Return TRUE if success, FALSE if error occurred.
** See msg->error for the specific error code.
**
**/
BOOL
SendMessage(struct ExecutiveMessage *message)
{
struct MsgPort *port;
/**
** Find Executive public message port and send the message.
** Wait for reply.
**
**/
Forbid();
if(port=FindPort(EXECUTIVEAPI_PORTNAME))
{
PutMsg(port, (struct Message *) message);
Permit();
WaitPort(message->message.mn_ReplyPort);
while(GetMsg(message->message.mn_ReplyPort))
;
if(!message->error)
return(TRUE);
}
else
{
/** Executive is not running **/
Permit();
}
return(FALSE);
}
/**
** Create a new task. The new task will send a message to Executive and ask
** that its priority is kept below all scheduled tasks. This is like having
** the following entry in Executive.prefs:
**
** TASK Example_childtask NOSCHEDULE BELOW
**
** Start the Top client and you'll se what happens to the childtask's
** priority.
**
**/
void
WatchMe(void)
{
if((parent_signal=AllocSignal(-1)) != -1)
{
parent_task = FindTask(NULL);
if(CreateNewProcTags( NP_Entry, (ULONG) WatchMe_entry,
NP_Name, (ULONG) "Example_childtask",
NP_Priority, 0,
NP_StackSize, STACK_SIZE,
TAG_DONE))
{
puts("Childtask started. Wait...");
Wait(1L << parent_signal);
puts("Childtask finished.");
}
else
{
FreeSignal(parent_signal);
puts("Can't create new process.");
exit(RETURN_FAIL);
}
FreeSignal(parent_signal);
}
else
{
puts("Can't allocate signal.");
exit(RETURN_FAIL);
}
}
void
WatchMe_entry(void)
{
struct ExecutiveMessage *message;
int t,i;
/** This routine needs DosBase, parent_task and parent_signal **/
GETA4();
if(message=AllocVec(sizeof(struct ExecutiveMessage), MEMF_PUBLIC|MEMF_CLEAR))
{
if(message->message.mn_ReplyPort=CreateMsgPort())
{
message->message.mn_Node.ln_Type = NT_MESSAGE;
message->message.mn_Length = sizeof(struct ExecutiveMessage);
/** Make sure this is always initialized to zero! **/
message->ident = 0;
message->command = EXAPI_CMD_WATCH;
message->task = FindTask(NULL);
message->value1 = EXAPI_WHICH_TASK;
message->value2 = EXAPI_TYPE_NOSCHEDULE;
message->value3 = EXAPI_PRI_BELOW;
/** Ignore error **/
SendMessage(message);
}
}
/** Use some CPU time **/
for(t=0;t<20;t++)
{
for(i=0;i<1000000;i++)
;
Delay(30);
}
if(message)
{
if(message->message.mn_ReplyPort)
DeleteMsgPort(message->message.mn_ReplyPort);
FreeVec(message);
}
/** Forbid so we can finish completely, before the parent cleans up. **/
Forbid();
Signal(parent_task, 1L << parent_signal);
}
/**
** Create three tasks with priorities -1, 0 and +1. Assume that this task's
** priority is 0. Configure Executive to schedule all childtasks of this
** task so that their priority is relative to this task's priority. This is
** like having the following entry in Executive.prefs:
**
** CHILDTASKS Example RELATIVE
**
** Start the Top client and you'll se what happens to childtask priorities.
** Try using the PGRP option with Ps: "ps PGRP=<this task's pid>". You'll
** see that the childtasks don't seem to use any CPU time. CPU usage is
** transferred to the parent task, because its CPU usage is used when
** scheduling priority is calculated.
**
** IMPORTANT! You'll have to issue the WATCH-command BEFORE starting any
** childtasks!
**
**/
void
WatchRelative(void)
{
msg->command = EXAPI_CMD_WATCH;
msg->task = FindTask(NULL);
msg->value1 = EXAPI_WHICH_CHILDTASKS;
msg->value2 = EXAPI_TYPE_RELATIVE;
if(!SendMessage(msg))
{
puts("EXAPI_CMD_WATCH command failed.");
if(msg->error == EXAPI_ERROR_ALREADY_WATCHED)
{
puts("You can only issue an EXAPI_CMD_WATCH command once for each task.");
puts("Executive remembers the task name, and if that task is started again,");
puts("it knows what to do with it.");
puts("If EXAPI_CMD_WATCH fails, check for EXAPI_ERROR_ALREADY_WATCHED");
puts("in msg->error. You can safely ignore this error. It's also possible");
puts("that user has put the task to Executive.prefs.");
}
else
exit(RETURN_FAIL);
}
if((parent_signal=AllocSignal(-1)) != -1)
{
struct Process *proc1, *proc2, *proc3;
parent_task = FindTask(NULL);
/** Forbid so all tasks start to run at the same time **/
Forbid();
proc1 = CreateNewProcTags(NP_Entry, (ULONG) WatchRelative_entry,
NP_Name, (ULONG) "Example_childtask1",
NP_Priority, -1,
NP_StackSize, STACK_SIZE,
TAG_DONE);
proc2 = CreateNewProcTags(NP_Entry, (ULONG) WatchRelative_entry,
NP_Name, (ULONG) "Example_childtask2",
NP_Priority, 0,
NP_StackSize, STACK_SIZE,
TAG_DONE);
proc3 = CreateNewProcTags(NP_Entry, (ULONG) WatchRelative_entry,
NP_Name, (ULONG) "Example_childtask3",
NP_Priority, 1,
NP_StackSize, STACK_SIZE,
TAG_DONE);
Permit();
if(proc1) active_tasks++;
if(proc2) active_tasks++;
if(proc3) active_tasks++;
if(active_tasks)
{
puts("Childtasks started. Wait...");
do {
Wait(1L << parent_signal);
} while(active_tasks);
puts("Childtasks finished.");
}
else
{
FreeSignal(parent_signal);
puts("Can't create new process.");
exit(RETURN_FAIL);
}
FreeSignal(parent_signal);
}
else
{
puts("Can't allocate signal.");
exit(RETURN_FAIL);
}
}
void
WatchRelative_entry(void)
{
int t,i;
/** We need DosBase, parent_task, parent_signal and active_tasks **/
GETA4();
/** Use some CPU time **/
for(t=0;t<20;t++)
{
for(i=0;i<350000;i++)
;
Delay(40);
}
/** Forbid so we can finish completely, before the parent cleans up. **/
Forbid();
active_tasks--;
Signal(parent_task, 1L << parent_signal);
}