/****** amiga.lib/CreateTask ***************************/
/*
  Copyright (c) 1988 Commodore-Amiga, Inc.
 
  Executables based on this information may be used in software
  for Commodore Amiga computers.  All other rights reserved.
 
  This information is provided "as is"; no warranties are made.
  All use is at your own risk, and no liability or responsibility is assumed.
*/


#include "exec/types.h"
#include "exec/tasks.h"
#include "exec/memory.h"

#include "proto/exec.h"
/*
#include "functions.h"
*/

/* the template for the mementries.  Unfortunately, this is hard to
 * do from C; mementries have unions, and they cannot be statically
 * initialized...
 *
 * In the interest of simplicity I recreate the mem entry structures
 * here with appropriate sizes.  We will copy this to a local
 * variable and set the stack size to what the user specified,
 * then attempt to actually allocate the memory.
 */
#define ME_TASK         0
#define ME_STACK        1
#define NUMENTRIES      2

struct FakeMemEntry {
    ULONG fme_Reqs;
    ULONG fme_Length;
};

struct FakeMemList {
    struct Node fml_Node;
    UWORD       fml_NumEntries;
    struct FakeMemEntry fml_ME[NUMENTRIES];
} TaskMemTemplate = {
    { 0 },                                              /* Node */
    NUMENTRIES,                                         /* num entries */
    {                                                   /* actual entries: */
	{ MEMF_PUBLIC | MEMF_CLEAR, sizeof( struct Task ) },    /* task */
	{ MEMF_CLEAR,   0 }                                     /* stack */
    }
};




struct Task * Create68kTask( char *name, ULONG pri, APTR initPC, ULONG stackSize )
{
struct Task *newTask;
struct FakeMemList fakememlist;
struct MemList *ml;
struct List *list;

    /* round the stack up to longwords... */
    stackSize = (stackSize +3) & ~3;

    /*
     * This will allocate two chunks of memory: task of PUBLIC
     * and stack of PRIVATE
     */
    fakememlist = TaskMemTemplate;
    fakememlist.fml_ME[ME_STACK].fme_Length = stackSize;

    ml = (struct MemList *)AllocEntry( (struct MemList *)&fakememlist );

    if(! ml )
	return( NULL );

    /* set the stack accounting stuff */
    newTask = (struct Task *) ml->ml_ME[ME_TASK].me_Addr;

    newTask->tc_SPLower = ml->ml_ME[ME_STACK].me_Addr;
    newTask->tc_SPUpper = (APTR)((ULONG)(newTask->tc_SPLower) + stackSize);
    newTask->tc_SPReg   = newTask->tc_SPUpper;

    /* misc task data structures */
    newTask->tc_Node.ln_Type = NT_TASK;
    newTask->tc_Node.ln_Pri  = pri;
    newTask->tc_Node.ln_Name = name;

    /* add it to the tasks memory list */
    //NewList( &newTask->tc_MemEntry );
    list = &newTask->tc_MemEntry;
    list->lh_TailPred = (struct Node *)&(list->lh_Head);
    list->lh_Tail = NULL;
    list->lh_Head = (struct Node *)&(list->lh_Tail);
    AddHead( &newTask->tc_MemEntry, (struct Node *)ml );

    /* add the task to the system -- use the default final PC */
    AddTask( newTask, initPC, 0L );
    return( newTask );
}


/****** amiga.lib/DeleteTask **********************************/

void DeleteTask( tc )
struct Task *tc;
{
    /* because we added a MemList structure to the tasks's TC_MEMENTRY
     * structure, all the memory will be freed up for us! */
    RemTask( tc );
}
