1 #ifndef EXEC_TASKS_H
    2 #define EXEC_TASKS_H
    3 
    4 /*
    5 	exec task definitions (V51)
    6 
    7 	Copyright © 2002-2025 The MorphOS Development Team, All Rights Reserved.
    8 */
    9 
   10 #ifndef EXEC_NODES_H
   11 # include <exec/nodes.h>
   12 #endif
   13 
   14 #ifndef EXEC_LISTS_H
   15 # include <exec/lists.h>
   16 #endif
   17 
   18 #ifndef EXEC_PORTS_H
   19 # include <exec/ports.h>
   20 #endif
   21 
   22 #pragma pack(2)
   23 
   24 
   25 struct ETask;
   26 
   27 struct Task
   28 {
   29 	struct Node    tc_Node;
   30 	UBYTE          tc_Flags;
   31 	UBYTE          tc_State;
   32 	BYTE           tc_IDNestCnt;
   33 	BYTE           tc_TDNestCnt;
   34 	ULONG          tc_SigAlloc;
   35 	ULONG          tc_SigWait;
   36 	ULONG          tc_SigRecvd;
   37 	ULONG          tc_SigExcept;
   38 #if 0
   39 	UWORD          tc_TrapAlloc;
   40 	UWORD          tc_TrapAble;
   41 #else
   42 	struct ETask  *tc_ETask;
   43 #endif
   44 	APTR           tc_ExceptData;
   45 	APTR           tc_ExceptCode;
   46 	APTR           tc_TrapData;
   47 	APTR           tc_TrapCode;
   48 	APTR           tc_SPReg;
   49 	APTR           tc_SPLower;
   50 	APTR           tc_SPUpper;
   51 	VOID         (*tc_Switch)(VOID);        /*** OBSOLETE ***/
   52 	VOID         (*tc_Launch)(VOID);        /*** OBSOLETE ***/
   53 	struct List    tc_MemEntry;
   54 	APTR           tc_UserData;
   55 };
   56 
   57 /*
   58  * Please use these macros in the future to declare, define and reference
   59  * task codestarts. That way we can easily change the way SysBase is passed
   60  * to a task to avoid ABSEXECBASE.
   61  *
   62  * ABOX_TASKPROTO(void,TaskStart,void *);
   63  * ABOX_TASK(void,TaskStart,void *Arg1)
   64  * {
   65  *    ABOX_DEFTASKSYSBASE;
   66  * }
   67  *
   68  * NewCreateTask(TASKTAG_PC,ABOX_TASKREF(TaskStart),TASKTAG_PPC_ARG1,Arg1,...,TAG_DONE);
   69  */
   70 #define	ABOX_TASKREF(n)			n##_start
   71 #define	ABOX_TASKPROTO(t,n,...)	t n##_start(__VA_ARGS__)
   72 #define	ABOX_TASK(t,n,...)		t n##_start(__VA_ARGS__)
   73 #define ABOX_GETTASKSYSBASE		MyEmulHandle->SuperHandle->GlobalSysBase
   74 #define ABOX_DEFTASKSYSBASE		struct ExecBase *SysBase=ABOX_GETTASKSYSBASE
   75 
   76 #define TB_PROCTIME     0
   77 #define TB_ETASK        3
   78 #define TB_STACKCHK     4
   79 #define TB_EXCEPT       5
   80 #define TB_SWITCH       6
   81 #define TB_LAUNCH       7
   82 
   83 #define TF_PROCTIME     (1 << TB_PROCTIME)
   84 #define TF_ETASK        (1 << TB_ETASK)
   85 #define TF_STACKCHK     (1 << TB_STACKCHK)
   86 #define TF_EXCEPT       (1 << TB_EXCEPT)
   87 #define TF_SWITCH       (1 << TB_SWITCH)
   88 #define TF_LAUNCH       (1 << TB_LAUNCH)
   89 
   90 #define TS_INVALID      0
   91 #define TS_ADDED        1
   92 #define TS_RUN          2
   93 #define TS_READY        3
   94 #define TS_WAIT         4
   95 #define TS_EXCEPT       5
   96 #define TS_REMOVED      6
   97 
   98 #define SIGB_ABORT      0
   99 #define SIGB_CHILD      1
  100 #define SIGB_BLIT       4
  101 #define SIGB_SINGLE     4
  102 #define SIGB_INTUITION  5
  103 #define SIGB_NET        7
  104 #define SIGB_DOS        8
  105 
  106 #define SIGF_ABORT      (1 << SIGB_ABORT)
  107 #define SIGF_CHILD      (1 << SIGB_CHILD)
  108 #define SIGF_BLIT       (1 << SIGB_BLIT)
  109 #define SIGF_SINGLE     (1 << SIGB_SINGLE)
  110 #define SIGF_INTUITION  (1 << SIGB_INTUITION)
  111 #define SIGF_NET        (1 << SIGB_NET)
  112 #define SIGF_DOS        (1 << SIGB_DOS)
  113 
  114 
  115 struct TaskTrapMessage
  116 {
  117 	struct Message  Message;        /* Message Header */
  118 	struct Task    *Task;           /* connected Task */
  119 	ULONG           Version;        /* version of the structure */
  120 	ULONG           Type;           /* Exception Type */
  121 	ULONG           DAR;            /* Exception Address Register */
  122 	ULONG           DSISR;          /* Exception DSISR Reg */
  123 
  124 	/* This is undiscovered land...
  125 	 * never assume a size of this structure
  126 	 */
  127 };
  128 
  129 #define VERSION_TASKTRAPMESSAGE  0x0
  130 
  131 /* Added in exec 50.67 */
  132 /*
  133  * Exec has now a more sophisticated 68k(emulation) trap management.
  134  * In reality it's just a new system wide traphandler who sends logserver
  135  * the msg and if this msg is replied it uses the new emulation state.
  136  */
  137 struct TaskTrapMessage_68k
  138 {
  139 	struct Message          Message;        /* Message Header */
  140 	struct Task             *Task;          /* connected Task */
  141 	ULONG                   Version;        /* version of the structure */
  142 	ULONG                   Type;           /* Exception Type */
  143 	ULONG                   Format;         /* Exception Stackframe Format */
  144 	void                    *Address;       /* Hit Address */
  145 	ULONG                   FLSW;
  146 	struct EmulHandle       *MyEmulHandle;
  147 };
  148 
  149 #define VERSION_TASKTRAPMESSAGE_68K     0x0
  150 
  151 
  152 struct ETask
  153 {
  154 	struct Message          Message;
  155 	struct Task            *Parent;
  156 	ULONG                   UniqueID;
  157 	struct MinList          Children;
  158 	UWORD                   TrapAlloc;
  159 	UWORD                   TrapAble;
  160 	ULONG                   Result1;
  161 	void                   *Result2;
  162 	struct MsgPort          MsgPort;
  163 
  164 	/* Don't touch!!!!!!!!!..there'll be an interface
  165 	 * sooner than later.
  166 	 * New Entries...most of the above entries
  167 	 * are only there for structure compatability.
  168 	 * They have no meaning as the OS never supported
  169 	 * them.
  170 	 */
  171 
  172 	/* A Task Pool for the task.
  173 	 */
  174 	void                   *MemPool;
  175 
  176 	/* PPC's Stack Lower Ptr
  177 	 * The initial stack is allocated through
  178 	 * AllocVec, so a FreeVec(ETask->PPCSPLower);
  179 	 * would work.
  180 	 * If you use PPCStackSwap you must allocate
  181 	 * your stack block with AllocVec();
  182 	 */
  183 	void                   *PPCSPLower;
  184 
  185 	/* PPC's Stack Upper Ptr
  186 	 */
  187 	void                   *PPCSPUpper;
  188 	void                   *PPCRegFrame;
  189 	void                   *PPCLibData;
  190 
  191 	/* On a PPC exception this msgport
  192 	 * is sent an exception msg....
  193 	 * the task is stopped until somebody
  194 	 * wakes it up again.
  195 	 * (asynchron exception interface)
  196 	 * If this Port is NULL the message is
  197 	 * sent to SysBase->ex_PPCTrapMsgPort.
  198 	 */
  199 	struct MsgPort         *PPCTrapMsgPort;
  200 	struct TaskTrapMessage *PPCTrapMessage;
  201 
  202 	/* This is undiscovered land...
  203 	 * never assume a size of this structure
  204 	 */
  205 };
  206 
  207 struct TaskInitExtension
  208 {
  209 	/* Must be filled with TRAP_PPCTASK
  210 	*/
  211 	UWORD           Trap;
  212 	UWORD           Extension;      /* Must be set to 0 */
  213 	struct TagItem *Tags;
  214 };
  215 
  216 #define TASKTAG_DUMMY           (TAG_USER + 0x100000)
  217 
  218 /* Ptr to an ULONG Errorfield where a better error description
  219  * can be stored.
  220  */
  221 #define TASKTAG_ERROR           (TASKTAG_DUMMY + 0x0)
  222 
  223 /* Code type
  224  * can be stored.
  225  */
  226 #define TASKTAG_CODETYPE        (TASKTAG_DUMMY + 0x1)
  227 
  228 /* Start PC
  229  * code must be of TASKTAG_CODETYPE
  230  */
  231 #define TASKTAG_PC              (TASKTAG_DUMMY + 0x2)
  232 
  233 /* Final PC
  234  * code must be of TASKTAG_CODETYPE
  235  */
  236 #define TASKTAG_FINALPC         (TASKTAG_DUMMY + 0x3)
  237 
  238 /* Stacksize...Default 8192
  239  */
  240 #define TASKTAG_STACKSIZE       (TASKTAG_DUMMY + 0x4)
  241 
  242 /* Std Stacksize...
  243  * Default(use the stack defined by tc_SPLower..tc_SPUpper)
  244  */
  245 #define TASKTAG_STACKSIZE_M68K  (TASKTAG_DUMMY + 0x5)
  246 
  247 /*
  248  * specify task name, name is copied
  249  */
  250 #define TASKTAG_NAME            (TASKTAG_DUMMY + 0x6)
  251 
  252 /*
  253  * tc_UserData
  254 */
  255 #define TASKTAG_USERDATA        (TASKTAG_DUMMY + 0x7)
  256 
  257 /*
  258  * Task priority
  259  */
  260 #define TASKTAG_PRI             (TASKTAG_DUMMY + 0x8)
  261 
  262 /* 
  263  * Pool's Puddlesize
  264  */
  265 #define TASKTAG_POOLPUDDLE      (TASKTAG_DUMMY + 0x9)
  266 
  267 /* 
  268  * Pool's ThreshSize
  269  */
  270 #define TASKTAG_POOLTHRESH      (TASKTAG_DUMMY + 0xa)
  271 
  272 
  273 /* PPC First Argument..gpr3
  274  */
  275 #define TASKTAG_PPC_ARG1        (TASKTAG_DUMMY + 0x10)
  276 
  277 /* PPC First Argument..gpr4
  278  */
  279 #define TASKTAG_PPC_ARG2        (TASKTAG_DUMMY + 0x11)
  280 
  281 /* PPC First Argument..gpr5
  282  */
  283 #define TASKTAG_PPC_ARG3        (TASKTAG_DUMMY + 0x12)
  284 
  285 /* PPC First Argument..gpr6
  286  */
  287 #define TASKTAG_PPC_ARG4        (TASKTAG_DUMMY + 0x13)
  288 
  289 /* PPC First Argument..gpr7
  290  */
  291 #define TASKTAG_PPC_ARG5        (TASKTAG_DUMMY + 0x14)
  292 
  293 /* PPC First Argument..gpr8
  294  */
  295 #define TASKTAG_PPC_ARG6        (TASKTAG_DUMMY + 0x15)
  296 
  297 /* PPC First Argument..gpr9
  298  */
  299 #define TASKTAG_PPC_ARG7        (TASKTAG_DUMMY + 0x16)
  300 
  301 /* PPC First Argument..gpr10
  302  */
  303 #define TASKTAG_PPC_ARG8        (TASKTAG_DUMMY + 0x17)
  304 
  305 
  306 
  307 /*
  308  * Startup message to be passed to task/process, ReplyMsg'd at RemTask()
  309  * ti_Data: struct Message *
  310  */
  311 #define TASKTAG_STARTUPMSG      (TASKTAG_DUMMY + 0x18)
  312 
  313 /*
  314  * Create internal MsgPort for task/process, deleted at RemTask()
  315  * ti_Data: struct MsgPort **, can be NULL
  316  */
  317 #define TASKTAG_TASKMSGPORT     (TASKTAG_DUMMY + 0x19)
  318 
  319 /*
  320  * Set unitial tc_Flags
  321  * ti_Data: UBYTE
  322  */
  323 #define TASKTAG_FLAGS           (TASKTAG_DUMMY + 0x1a)
  324 
  325 
  326 /*
  327  * Extra memory to allocate after task structure, the extra memory is
  328  * cleared
  329  * ti_Data: ULONG
  330  */
  331 #define TASKTAG_TCBEXTRASIZE    (TASKTAG_DUMMY + 0x1c)
  332 
  333 
  334 
  335 
  336 #define CODETYPE_M68K  0x0
  337 /*
  338  * System V4 ABI
  339  */
  340 #define CODETYPE_PPC   0x1
  341 
  342 
  343 #define TASKERROR_OK        0
  344 #define TASKERROR_NOMEMORY  1
  345 
  346 
  347 /*
  348  * Stack swap structure as passed to StackSwap() and PPCStackSwap()
  349  */
  350 struct StackSwapStruct
  351 {
  352 	APTR  stk_Lower;        /* Lowest byte of stack */
  353 	ULONG stk_Upper;        /* Upper end of stack (size + Lowest) */
  354 	APTR  stk_Pointer;      /* Stack pointer at switch point */
  355 };
  356 
  357 struct PPCStackSwapArgs
  358 {
  359 	ULONG Args[8];          /* The C register arguments from gpr3..gpr11 */
  360 };
  361 
  362 
  363 
  364 /*
  365  * NewGetTaskAttrsA(),  NewSetTaskAttrsA() tags
  366  */
  367 
  368 #define TASKINFOTYPE_ALLTASK            0x0
  369 #define TASKINFOTYPE_NAME               0x1
  370 #define TASKINFOTYPE_PRI                0x2
  371 #define TASKINFOTYPE_TYPE               0x3
  372 #define TASKINFOTYPE_STATE              0x4
  373 #define TASKINFOTYPE_FLAGS              0x5
  374 #define TASKINFOTYPE_SIGALLOC           0x6
  375 #define TASKINFOTYPE_SIGWAIT            0x7
  376 #define TASKINFOTYPE_SIGRECVD           0x8
  377 #define TASKINFOTYPE_SIGEXCEPT          0x9
  378 #define TASKINFOTYPE_EXCEPTDATA         0xa
  379 #define TASKINFOTYPE_EXCEPTCODE         0xb
  380 #define TASKINFOTYPE_TRAPDATA           0xc
  381 #define TASKINFOTYPE_TRAPCODE           0xd
  382 #define TASKINFOTYPE_STACKSIZE_M68K     0xe
  383 #define TASKINFOTYPE_STACKSIZE          0xf
  384 #define TASKINFOTYPE_USEDSTACKSIZE_M68K 0x10
  385 #define TASKINFOTYPE_USEDSTACKSIZE      0x11
  386 #define TASKINFOTYPE_TRAPMSGPORT        0x12
  387 #define TASKINFOTYPE_STARTUPMSG         0x13
  388 #define TASKINFOTYPE_TASKMSGPORT        0x14
  389 #define TASKINFOTYPE_POOLPTR            0x15
  390 #define TASKINFOTYPE_POOLMEMFLAGS       0x16
  391 #define TASKINFOTYPE_POOLPUDDLESIZE     0x17
  392 #define TASKINFOTYPE_POOLTHRESHSIZE     0x18
  393 
  394 /*
  395  * Task Scheduler statistics (exec 50.42)
  396  */
  397 #define TASKINFOTYPE_NICE                  0x19
  398 #define TASKINFOTYPE_AGETICKS              0x1a
  399 #define TASKINFOTYPE_CPUTIME               0x1b
  400 #define TASKINFOTYPE_LASTSECCPUTIME        0x1c
  401 #define TASKINFOTYPE_RECENTCPUTIME         0x1d
  402 #define TASKINFOTYPE_VOLUNTARYCSW          0x1e
  403 #define TASKINFOTYPE_INVOLUNTARYCSW        0x1f
  404 #define TASKINFOTYPE_LASTSECVOLUNTARYCSW   0x20
  405 #define TASKINFOTYPE_LASTSECINVOLUNTARYCSW 0x21
  406 /* Added in exec 50.45 */
  407 #define TASKINFOTYPE_LAUNCHTIMETICKS       0x22
  408 #define TASKINFOTYPE_LAUNCHTIMETICKS1978   0x23
  409 #define TASKINFOTYPE_PID_CLI               0x24
  410 /* Added in exec 50.54 */
  411 #define TASKINFOTYPE_SPLOWER               0x26
  412 #define TASKINFOTYPE_SPUPPER               0x27
  413 #define TASKINFOTYPE_SPLOWER_M68K          0x28
  414 #define TASKINFOTYPE_SPUPPER_M68K          0x29
  415 #define TASKINFOTYPE_NAMECOPY              0x2a
  416 /*
  417  * Get/Set task tc_UserData
  418  *     Data: ULONG start
  419  * DataSize: sizeof(ULONG)
  420  * Added in exec 50.63
  421  */
  422 #define TASKINFOTYPE_USERDATA           0x2b
  423 /*
  424  * Tag used to restart a suspended task
  425  *     Data: ULONG start
  426  * DataSize: sizeof(ULONG)
  427  * Set 'start' to nonzero to really start the task.
  428  * Returns sizeof(ULONG) if suspended task was successfully restarted.
  429  * NOTE: The task will get run immediately if it has higher priority
  430  * than the caller and the task switching has not been disabled.
  431  * Added in exec 50.63
  432  */
  433 #define TASKINFOTYPE_RESURRECT_TASK     0x2c
  434 /*
  435  * Get/Set task emulhandle
  436  *     Data: APTR emulhandle
  437  * DataSize: sizeof(APTR)
  438  * Added in exec 50.63
  439  */
  440 #define TASKINFOTYPE_EMULHANDLE         0x2d
  441 /*
  442  * Get task exception count
  443  *     Data: ULONG count
  444  * DataSize: sizeof(ULONG)
  445  * Added in exec 50.67
  446  */
  447 #define TASKINFOTYPE_EXCEPTIONCOUNT     0x2e
  448 /*
  449  * Get task hit count
  450  *     Data: ULONG count
  451  * DataSize: sizeof(ULONG)
  452  * Added in exec 50.67
  453  */
  454 #define TASKINFOTYPE_HITCOUNT           0x2f
  455 /*
  456  * Get/Set task max hit count.
  457  * If more hits happen the task is put to sleep.
  458  *     Data: ULONG count
  459  * DataSize: sizeof(ULONG)
  460  * Added in exec 51.3
  461  */
  462 #define TASKINFOTYPE_MAXHITCOUNT        0x30
  463 /*
  464  * Get task alert count
  465  *     Data: ULONG count
  466  * DataSize: sizeof(ULONG)
  467  * Added in exec 51.13
  468  */
  469 #define TASKINFOTYPE_ALERTCOUNT         0x31
  470 /*
  471  * Get/Set task max alert count.
  472  * If more alerts happen the task is put to sleep.
  473  *     Data: ULONG count
  474  * DataSize: sizeof(ULONG)
  475  * Added in exec 51.13
  476  */
  477 #define TASKINFOTYPE_MAXALERTCOUNT      0x32
  478 
  479 /*
  480  * Get task unique ID.
  481  * This ID is unique to every task.
  482  *     Data: ULONG id
  483  * DataSize: sizeof(ULONG)
  484  * Added in exec 51.14
  485  */
  486 #define TASKINFOTYPE_PID                0x33
  487 
  488 /*
  489  * Returns task stack history. This is safe to call for the task itself, and
  490  * using it on foreign tasks may give unpredictable results. At minimum the
  491  * results will get stale unless if you properly extract information while
  492  * keeping task scheduling locked.
  493  *
  494  * This info type is used to fetch struct TaskStackHistoryEntry records
  495  * that hold the call stack of the task. Pass pointer to the struct
  496  * TaskStacHistoryEntry array. The DataSize is used the pass the total size
  497  * of the array, and the return value will contain the amount of data filled
  498  * to the array. The return size is the total size of the filled array, so
  499  * divide by sizeof(struct TaskStackHistoryEntry) to get number of entries.
  500  *
  501  * You can skip stack frames by using TASKINFOTAG_STACKHISTORY_SKIPFRAMES
  502  * tag. Pass a number of frames to skip, default is 0, where no skipping is
  503  * done. If you're calling NewGetTaskAttrs function yourself for your own
  504  * task from a debug dump function, you might want to use skip value of
  505  * 1 to omit the debug function itself from the stack history.
  506  *
  507  *     Data: struct TaskStackHistoryEntry *
  508  * DataSize: numentries * sizeof(struct TaskStackHistoryEntry)
  509  * Added in exec 51.54
  510  */
  511 #define TASKINFOTYPE_PPC_STACKHISTORY   0x34
  512 
  513 #define TASKINFOTYPE_68K_NEWFRAME       0x50
  514 
  515 #define TASKINFOTYPE_PPC_SRR0           0x100
  516 #define TASKINFOTYPE_PPC_SRR1           0x101
  517 #define TASKINFOTYPE_PPC_LR             0x102
  518 #define TASKINFOTYPE_PPC_CTR            0x103
  519 #define TASKINFOTYPE_PPC_CR             0x104
  520 #define TASKINFOTYPE_PPC_XER            0x105
  521 #define TASKINFOTYPE_PPC_GPR            0x106
  522 #define TASKINFOTYPE_PPC_FPR            0x107
  523 #define TASKINFOTYPE_PPC_FPSCR          0x108
  524 #define TASKINFOTYPE_PPC_VSCR           0x109
  525 #define TASKINFOTYPE_PPC_VPR            0x10a
  526 #define TASKINFOTYPE_PPC_VSAVE          0x10b
  527 #define TASKINFOTYPE_PPC_FRAME          0x10c
  528 #define TASKINFOTYPE_PPC_FRAMESIZE      0x10d
  529 #define TASKINFOTYPE_PPC_NEWFRAME       0x10e
  530 
  531 #define TASKINFOTAG_DUMMY       (TAG_USER + 0x110000)
  532 /* Used with TASKINFOTYPE_ALLTASK
  533  */
  534 #define TASKINFOTAG_HOOK        (TASKINFOTAG_DUMMY + 0x0)
  535 /* Used with TASKINFOTYPE_PPC_GPR,TASKINFOTYPE_PPC_FPR,TASKINFOTYPE_PPC_VMX
  536  * to define the copy area
  537  */
  538 #define TASKINFOTAG_REGSTART    (TASKINFOTAG_DUMMY + 0x1)
  539 /* Used with TASKINFOTYPE_PPC_GPR,TASKINFOTYPE_PPC_FPR,TASKINFOTYPE_PPC_VMX
  540  * to define the copy area
  541  */
  542 #define TASKINFOTAG_REGCOUNT    (TASKINFOTAG_DUMMY + 0x2)
  543 
  544 /*
  545  * NewSetTaskAttrsA(..,&TaskFrame68k,sizeof(struct TaskFrame68k),TASKINFOTYPE_68K_NEWFRAME,...);
  546  *
  547  */
  548 struct TaskFrame68k
  549 {
  550 	void  *PC;
  551 	UWORD  SR;
  552 	ULONG  Xn[15];
  553 };
  554 
  555 #define TSHE_VALID              0  /* Address is considered valid */
  556 #define TSHE_INVALID            1  /* Address doesn't look like valid */
  557 struct TaskStackHistoryEntry
  558 {
  559 	ULONG  tshe_Type;          /* Currently either TSHE_VALID or TSHE_INVALID */
  560 	IPTR   tshe_Address;       /* Function return address */
  561 };
  562 
  563 /* Used with TASKINFOTYPE_PPC_STACKHISTORY to skip frames
  564  */
  565 #define TASKINFOTAG_STACKHISTORY_SKIPFRAMES (TASKINFOTAG_DUMMY + 0x3)
  566 
  567 
  568 /*
  569  * Don't depend on these
  570  */
  571 #define DEFAULT_PPCSTACKSIZE  32768
  572 #define DEFAULT_M68KSTACKSIZE  2048
  573 #define DEFAULT_TASKPUDDLESIZE 4096
  574 #define DEFAULT_TASKTHRESHSIZE 4096
  575 
  576 #define PID_CURRENT     0
  577 
  578 
  579 /*
  580  * TLSAlloc (V51.46)
  581  */
  582 #define TLS_INVALID_INDEX       (0xffffffff)
  583 
  584 #define TLSTAG_DUMMY            (TAG_USER + 0x120000)
  585 /* Destructor function to call on task termination if the TLS value
  586  * is non-NULL. The function is called with as:
  587  * VOID function(APTR value, APTR userdata);
  588  */
  589 #define TLSTAG_DESTRUCTOR       (TLSTAG_DUMMY + 0x0)
  590 /* Userdata for the destructor function. Defaults to NULL.
  591  */
  592 #define TLSTAG_USERDATA         (TLSTAG_DUMMY + 0x1)
  593 
  594 
  595 #pragma pack()
  596 
  597 #endif