Code: Select all
NP_Output, Output(),
NP_Input, Input(),
NP_CloseOutput, 0,
NP_CloseInput, 0,
Code: Select all
// disable the next line and it won't leak
flag = !flag;
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <exec/exec.h>
#include <proto/dos.h>
#include <proto/exec.h>
#define STC_STARTUP -2
#define STC_SHUTDOWN -1
struct Library *DOSBase = NULL;
struct DOSIFace *IDOS = NULL;
struct SubTaskMsg
{
struct Message stm_Message;
WORD stm_Command;
APTR stm_Parameter;
LONG stm_Result;
};
struct SubTask
{
struct Task *st_Task;
struct MsgPort *st_Port;
struct MsgPort *st_Reply;
APTR st_Data;
struct SubTaskMsg st_Message;
BPTR fh;
};
static LONG SendSubTaskMsg(struct SubTask *st, WORD command, APTR params)
{
st->st_Message.stm_Message.mn_ReplyPort = st->st_Reply;
st->st_Message.stm_Message.mn_Length = sizeof(struct SubTaskMsg);
st->st_Message.stm_Command = command;
st->st_Message.stm_Parameter = params;
st->st_Message.stm_Result = 0;
PutMsg((command == STC_STARTUP) ? &((struct Process *) st->st_Task)->pr_MsgPort : st->st_Port, (struct Message *) &st->st_Message);
WaitPort(st->st_Reply);
GetMsg(st->st_Reply);
return st->st_Message.stm_Result;
}
static APTR createproc(STRPTR name, APTR func, APTR data, APTR replyport, int stacksize, int prio)
{
struct SubTask *st;
st = AllocVec(sizeof(struct SubTask), MEMF_PUBLIC|MEMF_CLEAR);
if(st) {
st->st_Reply = replyport;
st->st_Data = data;
st->st_Task = (struct Task *) CreateNewProcTags(NP_Entry, (ULONG) func,
NP_Name, (ULONG) name,
NP_StackSize, (ULONG) stacksize,
NP_Output, Output(),
NP_Input, Input(),
NP_CloseOutput, 0,
NP_CloseInput, 0,
TAG_DONE);
if(st->st_Task) {
if(SendSubTaskMsg(st, STC_STARTUP, st)) return st;
}
FreeVec(st);
}
return NULL;
}
static void killproc(APTR handle)
{
struct SubTask *st = (struct SubTask *) handle;
SendSubTaskMsg(st, STC_SHUTDOWN, st);
FreeVec(st);
}
static void exitproc(APTR handle, int failed)
{
struct SubTask *st = (struct SubTask *) handle;
if(st->st_Port) DeleteMsgPort(st->st_Port);
if(st->fh) Close(st->fh);
// We reply after a Forbid() to make sure we're really gone when the main task continues.
Forbid();
st->st_Message.stm_Result = FALSE;
ReplyMsg((struct Message *) &st->st_Message);
}
static void setprocready(APTR handle)
{
struct SubTask *st = (struct SubTask *) handle;
st->st_Message.stm_Result = TRUE;
ReplyMsg((struct Message *) &st->st_Message);
}
static APTR initproc(APTR userdata, int debug)
{
struct Task *me = FindTask(NULL);
struct SubTask *st;
struct SubTaskMsg *stm;
WaitPort(&((struct Process *) me)->pr_MsgPort);
stm = (struct SubTaskMsg *) GetMsg(&((struct Process *)me)->pr_MsgPort);
st = (struct SubTask *) stm->stm_Parameter;
if(!(st->st_Port = CreateMsgPort())) {
exitproc(st, FALSE);
return NULL;
}
if(debug) st->fh = Open("CON:640/0/400/480/Proc Debug", MODE_NEWFILE);
return st;
}
static void prepprocexit(APTR handle)
{
struct SubTask *st = (struct SubTask *) handle;
GetMsg(st->st_Port);
}
static SAVEDS void sub_proc(void)
{
struct SubTask *st = initproc(NULL, FALSE);
ULONG quitsig;
setprocready(st);
quitsig = 1L << ((struct SubTask *) st)->st_Port->mp_SigBit;
for(;;) {
ULONG sigmask = Wait(quitsig);
if(sigmask & quitsig) break;
}
prepprocexit(st);
exitproc(st, FALSE);
}
int main(int argc, char *argv[])
{
struct MsgPort *replyport;
APTR handle[2] = {NULL, NULL};
int k, flag = 0;
DOSBase = OpenLibrary("dos.library", 0);
IDOS = (struct DOSIFace *) GetInterface(DOSBase, "main", 1, NULL);
replyport = CreateMsgPort();
for(k = 0; k < 3000; k++) {
if(!(handle[flag] = createproc("My subtask", (APTR) sub_proc, NULL, replyport, 32768, 0))) {
printf("Error!\n");
return 0;
}
// disable this line and it won't leak
flag = !flag;
if(handle[flag]) killproc(handle[flag]);
}
flag = !flag;
if(handle[flag]) killproc(handle[flag]);
DeleteMsgPort(replyport);
DropInterface((struct Interface *) IDOS);
CloseLibrary(DOSBase);
return 0;
}