65.9K
CodeProject 正在变化。 阅读更多。
Home

宏模拟中断级别下的多任务/阻塞代码

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (3投票s)

2009年6月7日

CPOL

13分钟阅读

viewsIcon

46198

downloadIcon

214

这是一组宏,可以在中断上下文中编写结构化代码,就像它是阻塞代码一样。

目录

  1. 引言
  2. 用法
    1. 基础
    2. 注释
    3. 安装
    4. 定义一个函数
    5. 启动一个新线程
    6. 调用一个函数
    7. 间接调用一个函数
    8. 从函数返回
    9. 获取返回码
    10. 结束一个线程
    11. 在线程内挂起
    12. 恢复一个线程
    13. 陷阱
    14. 父 IOB
    15. 用户上下文
    16. MT_CALL 事件序列
  3. 测试代码
  4. 许可证

1 引言

用户级别的系统使用多线程(也称为阻塞线程);然而,对于大多数中断驱动的代码,系统多线程并不常用。本文档描述了一组名为 MT_CALL 的宏,它模拟了多线程系统。使用这些宏有以下主要优点:

  1. 它只使用一个系统线程来支持数千个 I/O 线程;
  2. 不需要操作系统;
  3. 它支持中断级别的线程。

通常,在中断级别,工作可以根据 IO 处理程序的实现分派到任务级别或保留在中断级别。例如,缓存子系统和 RAID 子系统最好在任务级别实现。当缓存处理程序激活时,它可能会运行一个系统任务;但是,存储处理程序如果在中断级别运行,可能会更有效。MT_CALL 可以在中断级别运行并提供任务风格的编程。

这些宏用于在中​​断上下文中维护结构化编程技术。就像普通的任务级软件一样,使用多任务比使用传统的状态机更容易理解控制流。例如,在任务级别,由于操作系统提供了同步调用,我们很少使用状态机来执行磁盘 I/O。但是,在中​​断级别,同步 I/O 是不可能的,因此必须采用异步方法。通常,这需要复杂的状态机,而复杂的状态机需要深入了解所有状态如何协同工作。随着对软件提出新的要求,人们倾向于使用标志来避免新的状态。这些标志,甚至新状态的引入,通常会破坏“代码平衡”。

图 1(MT_CALL 序列)显示了一个示例流程。函数 A 使用 MT_START(路径 1)启动一个线程;线程(函数 B)开始执行并对函数 C 进行 MT_CALL(路径 2);函数 C 执行初始设置并执行一些 I/O,最终会导致中断;函数 C 使用 MT_SUSPEND 挂起操作;如路径 3 所示,会有一个隐藏的返回回到线程的初始创建者,线程创建者最终返回到操作系统,操作系统继续执行其他任务;发生中断(路径 4)并且流程继续到一个用户提供的处理程序;用户处理程序识别中断源并使用 MT_RESUME 恢复被挂起线程的执行(路径 5);被挂起的线程在 MT_SUSPEND 之后恢复控制,并使用 MT_RETURN 返回给其调用者(路径 6);MT_RESUME 通过调用前一个函数(路径 7)继续其活动,该函数确定已完成;函数 B 使用 MT_FINISHED(路径 8)终止线程;MT_FINISHED 会将控制权传递回 MT_RESUME,然后返回中断系统,最后返回到被中断的任务。

2 用法

2.1 基本用法

  • 要启动线程,请使用 MT_START
  • 使用 MT_STARTMT_CALL 调用的每个函数都必须是 MT_FUNCTION
  • 每个 MT_FUNCTION 都必须以 MT_ENTRY 开始,并使用 MT_RETURN 返回。
  • 如果 MT_FUNCTION 确定线程已完成,它将使用 MT_FINISHED
  • 如果线程必须因外部事件(例如,I/O 操作)而挂起,它将使用 MT_SUSPEND
  • 当外部事件发生时(例如,中断),处理程序将使用 MT_RESUME

2.2 注意事项

  • 堆栈上的变量在 MT_CALL 之后不会被保留;这些变量应放在您的个人 IOB 中。

2.3 设置

宏的使用方式如下:

  • 定义是否调试
  • MT_DEBUG 宏将执行堆栈检查,并打印每个宏的使用情况,从而允许您跟踪执行。例如:

    #define MT_DEBUG
  • 定义嵌套深度
  • 在任务控制块 (Task Control Block) 中设置一个堆栈,该堆栈保存每个 MT_CALL 的地址和状态。最大深度定义如下例所示:

    #define MT_MAX_DEPTH    3
  • 定义将使用的状态
  • 这些状态由 MT_STATES 构造定义。它们将被附加到名为 eMT_STATE 的内部枚举类型定义中。用逗号分隔每个状态,如果使用单独的行,请使用宏延续运算符。确保在最后一行省略运算符。例如:

    #define MT_STATES    \
        DO_SCAN,         \
        START_IO,        \
        TEST_UNIT_READY, \
        CHECKING_DRIVE,  \
        GETTING_TYPE,    \
        STOP_SCAN,       \
        EXECUTE_SCSI

    定义要用于任务控制块的指针。

    此指针封装在许多宏中。应用程序通常不使用它,但由于某些宏是通用的,因此可以将其用于这些情况。例如:

    #define MT_TCB_PTR pTcb
  • 包含宏文件
  • 例如

    #include <MT_CALL.H>
  • 定义任务控制块
  • 任务控制块是结构 MT_TCB,类型为 sMT_TCB,指针为 pMT_TCB。例如:

    sMT_TCB CheckDevicesTcb;
  • 定义 MT_Function 的原型
  • MT 函数使用 MT_FUNCTION 宏定义。例如:

    MT_FUNCTION ( CheckDevicesThread );

2.4 定义一个函数

当一个函数启动一个线程或由 MT_CALL 调用时,它必须被定义为 MT_FUNCTION。此外,它必须包含一个 MT_ENTRY 来定义正在使用的状态,并必须使用 MT_RETURN 来返回。它可以使用的宏包括 MT_STARTMT_CALLMT_SUSPENDMT_SET_TRAPMT_RESUMEMT_GOTO_TRAP(可能还有一些我忘记了)。

MT_NAME 宏用于定义函数的名称,MT_FUNCTION 宏用于构成函数。MT_NAME 宏将在其他一些宏中使用。此名称用于在任务控制块中标识函数名。

#undef MT_NAME
#define MT_NAME FunctionName
MT_FUNCTION ( FunctionName )

其中

FunctionName 是函数的名称。它必须出现在 MT_FUNCTION 宏中。如果需要,该宏可以写成 MT_FUNCTION( MT_NAME )(我更喜欢使用名称,这样我就可以轻松地复制粘贴来形成原型)。

函数不能有任何参数。这似乎令人遗憾,但无论如何,这就是面向状态的策略的本质(记住,这只是一个易于使用的状态机);抱歉。

MT_ENTRY 宏通常出现在自动变量定义之后。然而,它也可以出现在代码之后,如下面的示例所示。

MT_ENTRY
{
    MT_USE( StateName );
    MT_USE( AnotherStateName );
    MT_END_OF_LIST(); // to overcome warnings with some compilers
}

其中

StateNameAnotherStateName 是此函数中使用的状态的名称。对于使用的每个状态,必须有一个相应的 MT_CALLMT_SUSPEND,并且这些状态必须已在 MT_STATES 宏中定义。

MT_RETURN 宏用于从 MT_FUNCTION 返回。它不接受参数。

MT_RETURN();

注意

由于这些函数在调用 MT_RESUME 时实际上会被重新进入,因此任何自动变量在 MT_CALLMT_SUSPEND 之后都会丢失。因此,一些变量可能需要包含在用户定义的结构中。

这是一个例子。

#undef MT_NAME
#define MT_NAME CheckDevicesThread
MT_FUNCTION (CheckDevicesThread)
{
    // here is a case where an automatic variable is restored
    FUNNY_IOB *pIob = GetTheIob();
    MT_ENTRY()
    {
        MT_USE( CHECKING_DRIVE );
        MT_USE( GETTING_TYPE );
        MT_END_OF_LIST();
    }
    for(pIob->dn = 0; pIob->dn < MAX_DRIVES; pIob->dn++)
    {
        MT_CALL(CheckDrive, CHECKING_DRIVE);
    }
    MT_CALL(DoInquiry, GETTING_TYPE);
    MT_RETURN();
}

2.5 启动一个新线程

使用 MT_START 宏启动线程。启动后,线程就独立运行,有自己的执行路径。任务控制块将维护线程的状态(MT_TCB_PTR 用于此目的)。

调用顺序如下:

MT_START( pTcb, funToCall, pPrev );

其中

pTcb 是任务控制块的指针。
funToCall 是要调用的 MT_FUNCTION 的名称。
pPrev 是指向任务控制块的指针,该控制块代表当新线程完成时(使用 MT_FINISHED 宏)需要恢复的线程;如果没有前一个线程,则可能为 NULL

例如

MT_START( &CheckDevicesTcb, CheckDevicesThread, NULL );

在这种情况下,将调用函数 CheckDevicesThread()。任务控制块是 CheckDevicesTcb,并且没有涉及前一个任务控制块。

2.6 调用一个函数

每当调用一个必须挂起或导致挂起的函数时,它必须被编码为 MT_CALL,并且该函数必须被编码为 MT_FUNCTION

警告:进行 MT_CALL 时,自动(堆栈)变量在 MT_CALL 之后不会被保留。

调用顺序如下:

MT_CALL( funToCall, callState );

其中

funToCall 是要调用的 MT_FUNCTION
callState MT_STATES 中定义的,并在 MT_USE 中使用的一个枚举。

2.7 间接调用一个函数

可以通过以下方法间接调用函数。

使用双括号定义函数指针,例如:

MT_FUNCTION((*pFunction));

调用函数时,像对待普通 MT_CALL 一样引用该指针,如下所示:

MT_CALL( pFunction, callState );

以下是使用指针数组的示例:

MT_FUNCTION((*pFunction[10]));
...
MT_CALL( pFunction[j], callState );

2.8 从函数返回

当您必须从函数返回时,请使用 MT_RETURN 宏。

调用顺序如下:

MT_RETURN( returnCode )

其中

returnCode 是要返回给调用者的无符号整数;这可以通过 MT_GET_RETURN_CODE 宏获得。

2.9 获取返回码

MT_CALL 返回后,可以使用 MT_GET_RETURN_CODE 宏从被调用的函数获取返回码。

调用顺序如下:

rc = MT_GET_RETURN_CODE()

其中

rc 是一个无符号整数。它由 MT_RETURNMT_FINISHEDMT_GOTO_TRAP 的参数设置。

2.10 结束一个线程

当线程完成时,可以使用 MT_FINISHED 宏终止它。如果在 MT_START 宏中指定了前一个 TCB(参见上面的 pPrev),则 MT_FINISHED 宏将恢复使用 MT_START 的线程。

注意:使用 MT_START 并指定 pPrev 参数的线程必须使用 MT_SUSPEND 宏挂起,或者必须继续执行到 MT_SUPEND

调用顺序如下:

MT_FINISHED( returnCode )

其中

returnCode 是一个无符号整数。可以使用 MT_GET_RETURN_CODE() 获取它。

2.11 在线程内挂起

线程可以随时使用 MT_SUSPEND 宏挂起执行。挂起后,执行必须由用户提供的某些外部逻辑继续。此逻辑通常是中断过程的一部分;然而,该逻辑可能仅仅是满足适当的条件。

调用顺序如下:

MT_SUSPEND( callState )

其中

callState 是使用 MT_USE 宏提供的枚举之一。

2.12 恢复一个线程

可以在线程挂起之前或之后通过 MT_RESUME 宏恢复线程。这种“提前恢复”克服了可能发生的时序问题,即中断可能发生在 I/O 启动之后,但线程实际上执行 MT_SUSPEND 之前。

MT_RESUME 宏通常从中断服务例程中使用;但是,这不是必需的。

调用顺序如下:

MT_RESUME( pTcb )

其中

pTcb 是要恢复的线程的任务控制块的指针。

2.13 陷阱

线程可以将其执行“陷阱”到一个预定的点。当低级别发生错误时,这很有用。它类似于 C 中的 setjmp/longjmp 函数。

调用顺序如下:

MT_SET_TRAP( pEnv, callState )
MT_GOTO_TRAP(pEnv, returnCode )

其中

pEnv 是指向类型为 MT_ENV 的环境结构的指针。
callState 是陷阱的状态名称,并在 MT_USE 宏中命名。
returnCode 是一个可以通过 MT_GET_RETURN_CODE 宏获取的返回码。

用法

陷阱函数的使用方法如下:

  1. 使用 MT_SET_TRAP 宏设置陷阱返回点。
  2. 使用 MT_IS_TRAPPING 宏测试陷阱是否已发生。
  3. 使用 MT_GOTO_TRAP 宏执行陷阱。

这是一个例子。

sMT_ENV Environment;
...
MT_FUNCTION (CheckDrive)
{
    MT_ENTRY()
    {
        MT_USE( STOP_SCAN );
        MT_END_OF_LIST();
    }

    MT_SET_TRAP( &Environment, STOP_SCAN );
    if (MT_IS_TRAPPING())
    {
        printf("\nCheckDrive cought a trap, rc=%d", 
               MT_GET_RETURN_CODE());
        MT_RETURN(0);
    }
    ...
}
...
MT_FUNCTION (ExecuteScsi)
{
    MT_ENTRY()
    {
        ...
    }
    ...
   if( an error occurred )
    {
        printf("\nTrapping in ExecuteScsi");
        MT_GOTO_TRAP( &Environment, 9876);
        // MT_GOTO_TRAP will not return to here
    }
    ...
}

2.14 父 IOB

对于每个 TCB,有时可能有一个 I/O 结构 (IOB) 与之关联。当使用该方法时,通常需要获取包含 TCB 的 IOB 的地址。这可以通过几种方式完成;为了方便起见,可以使用 MT_GET_PARENT_STRUCT 宏。

调用顺序如下:

MT_GET_PARENT_STRUCT( structType, tcb )

其中

structType 是 IOB 结构的 typedef。
tcb 是 IOB 中 TCB 结构的名称。

2.15 用户上下文

通常,需要设置一些用户上下文,这些上下文将随线程一起传递。这可以使用 MT_SET_CONTEXT_PTRMT_GET_CONTEXT_PTR 宏来完成。

调用顺序如下:

MT_SET_CONTEXT_PTR( pTcb, ptr )
ptr = MT_GET_CONTEXT_PTR()

其中

pTcb 是指向要携带上下文指针的任务控制块的指针。
ptr 是用户上下文指针;它可以指向任何内容,宏不理解它。

2.16 MT_CALL 事件序列

参考图 1 - MT_CALL 事件序列,使用这些函数发生的事件序列如下:

路径 1 显示线程使用 MT_START 宏启动。这会初始化调用序列中命名的线程控制块 (TCB)。具体来说,当前状态 (currentState) 被设置为 -1。

  • 由于 MT_START 已将 currentState 初始化为 -1,因此新线程会继续执行 MT_ENTRY 语句。
  • 执行正常继续,路径 2 显示了一个 MT_CALL。这会增加 stackIndex,将当前函数(由 #define MT_NAME 命名)的地址添加到回调堆栈 (callStack) 中,并设置调用状态 (callState)。MT_CALL 还将 currentState 设置为 -1,以强制新函数通过 MT_ENTRY 语句。
  • 执行继续正常通过 MT_ENTRY 语句,然后到达 MT_SUSPEND 语句。

路径 3 显示返回到操作系统。MT_SUSPEND 也增加了 stackIndex,并将当前函数的地址添加进来,就像上面一样。现在,事情被暂停了。

  • 路径 3 返回到操作系统,因为 MT_SUSPEND 包含一个嵌入式 return NULL 语句。启动路径 2 的 MT_CALL 检查返回值,如果它是 NULL,它会重复 return NULL。序列中的任何其他 MT_CALL 也会做同样的事情,因此控制权返回到 MT_STARTMT_START 假设线程正在自由运行,并继续执行(在这种情况下,函数 A 实际上返回到操作系统)。注意:在 MT_SUSPEND 执行任何操作之前,它会检查是否已使用 MT_RESUME,如果已使用,则不执行任何操作(本图未显示示例)。

路径 4 显示中断发生。中断系统将控制权传递给用户处理程序,该处理程序在确定中断源后,使用 MT_RESUME 宏恢复线程的执行。

  • MT_RESUME 是一个循环,它使用 stackIndex 逐个调用函数,并为每个函数提供其保存的 callState。如果 MT_RESUME 发现 MT_SUSPEND 尚未执行,它只记录 MT_RESUME 已被使用的事实,然后什么也不做。这允许发生中断但 MT_SUSPEND 还没有机会执行的情况。

路径 5 显示恢复函数 C。现在,函数 C 中的 MT_ENTRY 执行一个 switch(callState),这会导致 goto 跳过 MT_SUSPEND

  • 执行继续沿着路径 5 到 MT_RETURN 的位置。

路径 6 显示 MT_RETURN 返回到用户处理程序。MT_RETURN 返回一个非 NULL 值,这使得 MT_RESUME 继续其循环。

路径 7 显示使用其 callState 调用前一个函数。这可能已经进行了更多的 MT_CALLMT_SUSPEND,在这种情况下,上述场景会继续发生。

  • 在我们的例子中,路径 7 进入了一个 MT_FINISHED 语句。如果在 MT_START 宏中没有提供前一个 TCB,MT_FINISHED 只会返回 NULL。这会导致一切返回到操作系统,因为当某些东西返回 NULL 时,MT_RESUME 会停止。
  • 如果函数 B 使用了 MT_SUSPEND,它也会返回 NULL,这也将导致 MT_RESUME 循环终止。

Sequence_of_events.jpg

图 1 - MT_CALL 事件序列

3 宏

/*-
 * Copyright (c) 1995, 2000, 2007 Edward S. Quicksall
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Edward S. Quicksall.
 * 3. Neither the name Edward S. Quicksall nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY EDWARD S. QUICKSALL AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EDWARD S. QUICKSALL OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


/*
#ifdef __KERNEL__
    #define PRINTF printk
#else
    #ifndef _ARC
        #define PRINTF printf
    #endif
#endif
*/
////////////////////////////////////////////////////////////////////////
//
//  Name:           MtCall.h
//  Description:    Simulates multi-tasking for interrupt driven code.
//  Returns:        none
//  Arguments:      none
//  Notes:          none
//
////////////////////////////////////////////////////////////////////////


//#define MT_DEBUG
//#define MT_DEBUG_PRINT

//  These default defines allow the .h file to be included when the
//  structures are needed but the actual MT_CALL macros are not
#ifndef MT_MAX_DEPTH
    #define MT_MAX_DEPTH    6 // the debugger picks this up by mistake so for
                              // debugging, make this the same as the real one
#endif
#ifndef MT_STATES
    #define MT_STATES   MT_NOTHING
#endif


// ----------------- pre-define issues -----------------------------------
#ifndef __MT_CALL_PREDEF__
#define __MT_CALL_PREDEF__

//  The things within __MT_CALL_PREDEF__ are needed by .h files which are used
//  before the formal use of MtCall.h

typedef struct MT_SEMAPHORE
{
    int             signaled;    // + means it has been signaled that many times
    struct MT_TCB   *pTcb;       // pointer to
} sMT_SEMAPHORE, *pMT_SEMAPHORE;

#endif  //  __MT_CALL_PREDEF__
// -----------------------------------------------------------------------



//  The definition of MT_MAX_DEPTH means this is the formal use of MtCall.h
//#ifdef MT_MAX_DEPTH

#ifndef __MT_CALL_H__
#define __MT_CALL_H__

#ifdef __KERNEL__
    #include <linux>
#else
    #include <stddef.h> // needed for offsetof macro
#endif

#ifdef WIN32
    #define MT_ENTER_DEBUGGER() _asm { int 3 }
#endif

#ifdef IDISX_MIPS_COMPILER
    #define MT_ENTER_DEBUGGER() printk("%d\n", *(unsigned int *)0)
#endif

#define MT_FUNCTION(funName) sMT_TCB * funName(struct MT_TCB *MT_TCB_PTR)

typedef enum MT_STATE
{
    MT_INITIAL_CALL = -1,
    MT_UNINITIALIZED    = 0,
    MT_STATES              
} eMT_STATE;

typedef struct MT_TCB * (*MT_FUNCTION_PTR) (struct MT_TCB *);

typedef struct MT_CALLBACK
{
    MT_FUNCTION_PTR pFunction;      // calling function
    eMT_STATE       functionState;  // state of the function (pFunction)
} sMT_CALLBACK, *pMT_CALLBACK;

typedef struct MT_TCB
{
    int             stackIndex;     // index into call stack
    sMT_CALLBACK    callStack[ MT_MAX_DEPTH ];  // call stack
    enum MT_STATE   currentState;   // (callStack.functionState)
    int             suspends;       // 1 if suspends, 0 if not, negative means
                                    // resumed that many times
    struct MT_TCB   *pPrevTcb;      // pointer to the previous TCB
    void            *pContext;      // pointer to a user IOB
    MT_FUNCTION_PTR pTrappingFunction; // ptr if GOTO_TRAP, 1 if
                                    // RESUME_AND_TRAP, else 0
    union
    {
        unsigned int    returnCode;     // a return code
        void            *returnContext; // not referenced, just to be sure there
                                        // is enough space for a pointer here
    } u;
} sMT_TCB, *pMT_TCB;

typedef struct MT_ENVIRONMENT
{
    eMT_STATE       currentState;   // (callStack.functionState)
    int             stackIndex;     // index into call stack
    sMT_CALLBACK    callBack;       // function and state to call back to
} sMT_ENVIRONMENT, *pMT_ENVIRONMENT;


////////////////////////////////////////////////////////////////////////
//
//  Name:           N/A
//  Description:    These are debug macros. They do nothing if MT_DEBUG is not
//                  defined.
//  Returns:        N/A
//  Arguments:      N/A
//  Notes:          MT_STACK_CHECK checks for a stack overflow
//                  MT_CLEAR_CALL clears the current call entry
//                  MT_CLEAR_ALL clears all entries in the stack
//                  MT_PRINTF is a simulation of printf
//
////////////////////////////////////////////////////////////////////////
#ifdef MT_DEBUG

    #ifdef WIN32
        #include <assert.h>
        #include>stdio.h>
    #endif

    //#define MT_ASSERT(a) assert(a)
    // I ran into a bug and the debugger would just exit upon a bad assertion.
    // Then, the int 3 just exited but I found that if I did the scanf first,
    // it worked.
    // Hence, the following macro for ASSERT has been created.
    //#define MT_ASSERT(exp) if (!(exp)) { char ch; PRINTF("\nAssert failed: "\
    // #exp", "__FILE__", press enter""\n"); scanf( "%c", &ch );\
    // MT_ENTER_DEBUGGER(); }
    #define MT_ASSERT(exp) if (!(exp)) { PRINTF("\nAssert failed: "\
      #exp", "__FILE__", %d\n", __LINE__); MT_ENTER_DEBUGGER(); }

    #define MT_STACK_CHECK(a)                                                  \
        MT_ASSERT ( ((a)->stackIndex+1) < (MT_MAX_DEPTH) );

      
#if 0   // This does not always work because if an MT_RESUME is the last resume
        // of a thread, the thread could free the memory where the TCB is
        // sitting and then (a) would point to garbage. A way to handle it could
        // be to clear it before the callback.
    #define MT_CLEAR_CALL(a)                                                   \
        if ((a) != NULL)                                                       \
        {                                                                      \
            (a)->currentState = MT_UNINITIALIZED;                              \
            (a)->callStack[ (a)->stackIndex+1 ].pFunction                      \
                              = NULL;                                          \
            (a)->callStack[ (a)->stackIndex+1 ].functionState                  \
                              = MT_UNINITIALIZED;                              \
        }
#else
    #define MT_CLEAR_CALL(a)
#endif

    #define MT_CLEAR_ALL(a)                                                    \
        {                                                                      \
            /* since "a" may have an "i" subscript on it, use a silly i */     \
            int iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii;                             \
            void *savedContext = (a)->pContext;                                \
            for (iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii = 0;                        \
                 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii < sizeof(sMT_TCB);          \
               ++iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)                            \
            {                                                                  \
                ((char *)(a))[iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii] = 0;          \
            }                                                                  \
            (a)->pContext = savedContext;                                      \
            (a)->stackIndex = -1; /* this is for MT_PRINTF in MT_START */      \
        }

    #ifdef MT_DEBUG_PRINT
        #define MT_PRINTF(a,b)                                                 \
        {                                                                      \
            /* since "a" may have an "i" subscript on it, use a silly i */     \
            int iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii;                             \
            for (iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii = 0;                        \
                 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii < (a)->stackIndex;          \
               ++iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii) PRINTF("    ");            \
        }                                                                      \
        PRINTF b;                                                              \
        PRINTF("\n");
    #else
        #define MT_PRINTF(a,b)
    #endif

#else
    #define MT_ASSERT(a)
    #define MT_STACK_CHECK(a)
    #define MT_CLEAR_CALL(a)
    #define MT_CLEAR_ALL(a)
    #define MT_PRINTF(a,b)
#endif

////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_START
//  Description:    Start a new thread
//  Returns:        none
//  Arguments:      pTcb = a pointer to a Task Control Block
//                  FunToCall = the function to call (don't supply arguments)
//                  pPrev = The current TCB if you will suspend waiting for 
//                  the new thread to use MT_FINISHED, otherwise NULL
//  Notes:          Don't forget to use MT_SUSPEND if you use pPrev.
//                  This will set the context pointer to NULL. That way, you
//                  can tell if the context has already been filled in when
//                  FunToCall is entered (!firstTime). See processLogin for
//                  an exmaple.
// 
//                  Don't clear pContext because it may have already been
//                  set before the MT_START was used.
//
////////////////////////////////////////////////////////////////////////
#define MT_START(pTcb,FunToCall,pPrev)                                         \
{                                                                              \
    MT_CLEAR_ALL( (pTcb) )                                                     \
    MT_PRINTF((pTcb),("MT_START "#FunToCall", TCB=%08X, "#pPrev"=%08X", pTcb,  \
                                                                     pPrev))   \
    (pTcb)->currentState = MT_INITIAL_CALL;                                    \
    (pTcb)->stackIndex  = -1;                                                  \
    (pTcb)->suspends = 0;                                                      \
    (pTcb)->pTrappingFunction = NULL;                                          \
    (pTcb)->u.returnCode = 0;                                                  \
    (pTcb)->pPrevTcb = pPrev;                                                  \
    FunToCall(pTcb);                                                           \
}                                                                              \


////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_ENTRY
//  Description:    Define the entry of an MT_FUNCTION. This will contain MT_USE
//                  macros.
//  Returns:        none
//  Arguments:      none
//  Notes:          
//
////////////////////////////////////////////////////////////////////////
#define MT_ENTRY()                                                             \
    switch( (MT_TCB_PTR)->currentState )                                       \


////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_USE
//  Description:    Define states to be used in the MT_FUNCTION
//  Returns:        N/A
//  Arguments:      A state that will be used in the function (it is OK
//                  to use the same state in two different functions)
//  Notes:
//
////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
    #define MT_USE(callState)                                                  \
        case callState:                                                        \
            goto MT_LABEL_##callState;                                         \
    MT_USE_##callState:                                                        \
        return NULL                                                            \


#else
    #define MT_USE(callState)                                                  \
        case callState:                                                        \
            goto MT_LABEL_##callState;

#endif


////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_RETURN
//  Description:    Return from an MT_FUNCTION
//  Returns:        N/A
//  Arguments:      code = a return code (use MT_GET_RETURN_CODE)
//  Notes:          If at the root level, do an MT_FINISHED
//
////////////////////////////////////////////////////////////////////////
#define MT_RETURN(code)                                                        \
{                                                                              \
    if ( (MT_TCB_PTR)->stackIndex == -1 )                                      \
    {                                                                          \
        MT_FINISHED(code)                                                      \
    }                                                                          \
    else                                                                       \
    {                                                                          \
        (MT_TCB_PTR)->u.returnCode = code;                                     \
        return MT_TCB_PTR;                                                     \
    }                                                                          \
}                                                                              \


////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_CALL
//  Description:    Call an MT_FUNCTION
//  Returns:        The value from MT_RETURN (use MT_GET_RETURN_CODE)
//  Arguments:      FunToCall is the function to call (no args in this)
//                  callState is the state of the calling function
//  Notes:          none
//
////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
    #define MT_CALL(FunToCall,callState)                                       \
    {                                                                          \
        MT_PRINTF(MT_TCB_PTR,("MT_CALL "#FunToCall", "#callState", TCB=%08X",  \
                                                               MT_TCB_PTR))    \
        MT_STACK_CHECK(MT_TCB_PTR)                                             \
        (MT_TCB_PTR)->currentState = MT_INITIAL_CALL;                          \
        ++(MT_TCB_PTR)->stackIndex;                                            \
        (MT_TCB_PTR)->callStack[ (MT_TCB_PTR)->stackIndex ].pFunction =        \
                                                           MT_NAME;            \
        (MT_TCB_PTR)->callStack[ (MT_TCB_PTR)->stackIndex ].functionState =    \
                                                               callState;      \
        if ( FunToCall(MT_TCB_PTR) == NULL )                                   \
        {                                                                      \
            goto MT_USE_##callState;                                           \
        }                                                                      \
        MT_LABEL_##callState:                                                  \
        --(MT_TCB_PTR)->stackIndex;                                            \
        MT_PRINTF(MT_TCB_PTR,("MT_RETURN "#FunToCall", "#callState", TCB=%08X",\
                                                                 MT_TCB_PTR))  \
    }                                                                          \



#else
    #define MT_CALL(FunToCall,callState)                                       \
    {                                                                          \
        MT_PRINTF(MT_TCB_PTR,("MT_CALL "#FunToCall", "#callState", TCB=%08X",  \
                                                                 MT_TCB_PTR))  \
        MT_STACK_CHECK(MT_TCB_PTR)                                             \
        (MT_TCB_PTR)->currentState = MT_INITIAL_CALL;                          \
        ++(MT_TCB_PTR)->stackIndex;                                            \
        (MT_TCB_PTR)->callStack[ (MT_TCB_PTR)->stackIndex ].pFunction =        \
                                                                  MT_NAME;     \
        (MT_TCB_PTR)->callStack[ (MT_TCB_PTR)->stackIndex ].functionState =    \
                                                               callState;      \
        if ( FunToCall(MT_TCB_PTR) == NULL )                                   \
        {                                                                      \
            return NULL;/*goto MT_USE_##callState;*/                           \
        }                                                                      \
        MT_LABEL_##callState:                                                  \
        --(MT_TCB_PTR)->stackIndex;                                            \
        MT_PRINTF(MT_TCB_PTR,("MT_RETURN "#FunToCall", "#callState", TCB=%08X",\
                                                                 MT_TCB_PTR))  \
    }                                                                          \



#endif

////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_SUSPEND/MT_RESUME
//  Description:    Suspend or resume a thread.
//  Returns:        none
//  Arguments:      callState = the state of the suspending thread
//  Notes:          none
//
////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
    #define MT_SUSPEND(callState)                                              \
    {                                                                          \
        ASSERT( (MT_TCB_PTR)->suspends <= 1 );                                 \
        ASSERT( (MT_TCB_PTR)->suspends >= -1 );                                \
        ++(MT_TCB_PTR)->suspends;                                              \
        if ((MT_TCB_PTR)->suspends == 1)                                       \
        {                                                                      \
            MT_PRINTF(MT_TCB_PTR,("MT_SUSPEND, "#callState", TCB=%08X",        \
                                                               MT_TCB_PTR))    \
            MT_STACK_CHECK(MT_TCB_PTR)                                         \
            ++(MT_TCB_PTR)->stackIndex;                                        \
            (MT_TCB_PTR)->callStack[ (MT_TCB_PTR)->stackIndex ].pFunction =    \
                                                               MT_NAME;        \
            (MT_TCB_PTR)->callStack[ (MT_TCB_PTR)->stackIndex ].functionState =\
                                                                   callState;  \
            goto MT_USE_##callState;                                           \
            MT_LABEL_##callState:                                              \
            --(MT_TCB_PTR)->stackIndex;                                        \
            MT_PRINTF(MT_TCB_PTR,("MT_RESUME,  "#callState", TCB=%08X",        \
                                                           MT_TCB_PTR))        \
        }                                                                      \
        else                                                                   \
        {                                                                      \
            MT_PRINTF(MT_TCB_PTR,("MT_SUSPEND, "#callState", TCB=%08X - "      \
                                                "already resumed", MT_TCB_PTR))\
        }                                                                      \
    }                                                                          \


#else
    #define MT_SUSPEND(callState)                                              \
    {                                                                          \
        ++(MT_TCB_PTR)->suspends;                                              \
        if ((MT_TCB_PTR)->suspends == 1)                                       \
        {                                                                      \
            MT_PRINTF(MT_TCB_PTR,("MT_SUSPEND, "#callState", TCB=%08X",        \
                                                           MT_TCB_PTR))        \
            MT_STACK_CHECK(MT_TCB_PTR)                                         \
            ++(MT_TCB_PTR)->stackIndex;                                        \
            (MT_TCB_PTR)->callStack[ (MT_TCB_PTR)->stackIndex ].pFunction =    \
                                                               MT_NAME;        \
            (MT_TCB_PTR)->callStack[ (MT_TCB_PTR)->stackIndex ].functionState =\
                                                                   callState;  \
            return NULL;/*goto MT_USE_##callState;*/                           \
            MT_LABEL_##callState:                                              \
            --(MT_TCB_PTR)->stackIndex;                                        \
            MT_PRINTF(MT_TCB_PTR,("MT_RESUME,  "#callState", TCB=%08X",        \
                                                           MT_TCB_PTR))        \
        }                                                                      \
        else                                                                   \
        {                                                                      \
            MT_PRINTF(MT_TCB_PTR,("MT_SUSPEND, "#callState", TCB=%08X - "      \
                                                "already resumed", MT_TCB_PTR))\
        }                                                                      \
    }                                                                          \




#endif


#define MT_RESUME(pTcb)                                                        \
{                                                                              \
    sMT_TCB *pNext;                                                            \
    pNext = pTcb;                                                              \
    ASSERT( pNext->suspends <= 1 );                                            \
    ASSERT( pNext->suspends >= -1 );                                           \
    --pNext->suspends;                                                         \
    if (pNext->suspends == 0)                                                  \
    {                                                                          \
        while (pNext != NULL && pNext->stackIndex >= 0)                        \
        {                                                                      \
            register sMT_TCB *pNext1;                                          \
            register int stackIndex;                                           \
            stackIndex = pNext->stackIndex;                                    \
            pNext->currentState = pNext->callStack[ stackIndex ].functionState;\
            pNext1 = (*pNext->callStack[ stackIndex ].pFunction)(pNext);       \
            MT_CLEAR_CALL( pNext );                                            \
            pNext = pNext1;                                                    \
        }                                                                      \
    }                                                                          \
}                                                                              \


////////////////////////////////////////////////////////////////////////
//
//  Name:       MT_FINISHED     
//  Description:Indicate that you are finished with the thread. If a
//              TCB was supplied with the MT_START, this will resume
//              the starting thread. Otherwise, the thread just dies.
//  Returns:    none    
//  Arguments:  A value to be saved for retrieval by MT_GET_RETURN_CODE    
//  Notes:      If the MT_START supplied a NULL for the previous TCB, then
//              the MT_FINISHED macro will cause the thread to just die out.
//
//  Important:  If the starting thread supplied a TCB, it is assumed that
//              it has also suspended (or will suspend) and is waiting for
//              this thread to finish. 
//
////////////////////////////////////////////////////////////////////////
#define MT_FINISHED(code)                                                      \
{                                                                              \
    MT_PRINTF(MT_TCB_PTR,("MT_FINISHED, TCB=%08X, pPrevTcb=%08X", MT_TCB_PTR,  \
                                                (MT_TCB_PTR)->pPrevTcb))       \
    if ((MT_TCB_PTR)->pPrevTcb == NULL)                                        \
    {                                                                          \
        MT_CLEAR_ALL(MT_TCB_PTR);                                              \
        return NULL;                                                           \
    }                                                                          \
    else                                                                       \
    {                                                                          \
        sMT_TCB *pPrev = (MT_TCB_PTR)->pPrevTcb;                               \
        pPrev->u.returnCode = code;                                            \
        ASSERT( (MT_TCB_PTR)->suspends <= 1 );                                 \
        ASSERT( (MT_TCB_PTR)->suspends >= -1 );                                \
        --pPrev->suspends;                                                     \
        if (pPrev->suspends == 0)                                              \
        {                                                                      \
            return pPrev;                                                      \
        }                                                                      \
        MT_PRINTF(MT_TCB_PTR,("MT_FINISHED, TCB=%08X, pPrevTcb=%08X - early "  \
                                                 "resume", MT_TCB_PTR, pPrev)) \
        return NULL;                                                           \
    }                                                                          \
}                                                                              \


////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_SET_TRAP/MT_GOTO_TRAP/MT_IS_TRAP
//  Description:    Setup a trap function
//  Returns:        none
//  Arguments:      pEnv = a pointer to an MT_ENV structure
//                  callState = the caller's state
//  Notes:          MT_SET_TRAP will setup so control will return if an
//                  MT_GOTO_TRAP.
//                  MT_IS_TRAP can be used to check if the return is from setup
//                  or a trap.
//                  
//                  MT_GOTO_TRAP is used to trap out of yourself and does not
//                  give control back to you so only use it within an
//                  MT_FUNCTION.
//
//                  MT_RESUME_AT_TRAP is similar to RESUME except that instead
//                  of resuming the thread at its suspended place, it
//                  resumes to the code that used MT_SET_TRAP. MT_RESUME_AT_TRAP
//                  will give control back to you so don't use it within
//                  an MT_FUNCTION.
//
////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
    #define MT_SET_TRAP(pEnv,callState)                                        \
        MT_PRINTF(MT_TCB_PTR, ("MT_SET_TRAP, TCB=%08X, ENV=%08X, "#callState,  \
                                                          MT_TCB_PTR, pEnv));  \
        (pEnv)->stackIndex   = (MT_TCB_PTR)->stackIndex;                       \
        /* it looks to me like (pEnv)->callBack.pFunction is not needed   */   \
        /* because the stackIndex will cause it to point to that function */   \
        /* anyway (Eddy)                                                  */   \
        (pEnv)->callBack.pFunction = MT_NAME;                                  \
        (pEnv)->callBack.functionState = callState;                            \
        (MT_TCB_PTR)->pTrappingFunction = NULL;                                \
        /* Use a goto to be sure MT_USE is in place */                         \
        if ((MT_TCB_PTR)->pTrappingFunction != NULL) goto MT_USE_##callState;  \
        MT_LABEL_##callState:                                                  \


#else
    #define MT_SET_TRAP(pEnv,callState)                                        \
        MT_PRINTF(MT_TCB_PTR, ("MT_SET_TRAP, TCB=%08X, ENV=%08X, "#callState,  \
                                                          MT_TCB_PTR, pEnv));  \
        (pEnv)->stackIndex   = (MT_TCB_PTR)->stackIndex;                       \
        /* it looks to me like (pEnv)->callBack.pFunction is not needed   */   \
        /* because the stackIndex will cause it to point to that function */   \
        /* anyway (Eddy)                                                  */   \
        (pEnv)->callBack.pFunction = MT_NAME;                                  \
        (pEnv)->callBack.functionState = callState;                            \
        (MT_TCB_PTR)->pTrappingFunction = NULL;                                \
        if ((MT_TCB_PTR)->pTrappingFunction != NULL) return NULL;              \
        MT_LABEL_##callState:                                                  \



#endif


#define MT_GOTO_TRAP(pEnv,code)                                                \
{                                                                              \
    (MT_TCB_PTR)->stackIndex = (pEnv)->stackIndex;                             \
    MT_PRINTF(MT_TCB_PTR,("MT_GOTO_TRAP, TCB=%08X, ENV=%08X", MT_TCB_PTR,      \
                                                                 pEnv));       \
    (MT_TCB_PTR)->currentState = (pEnv)->callBack.functionState;               \
    (MT_TCB_PTR)->pTrappingFunction = MT_NAME;                                 \
    (MT_TCB_PTR)->u.returnCode = code;                                         \
    if ( (*(pEnv)->callBack.pFunction)(MT_TCB_PTR) == NULL )                   \
    {                                                                          \
        return NULL;                                                           \
    }                                                                          \
    else                                                                       \
    {                                                                          \
        sMT_TCB *pNext;                                                        \
        pNext = MT_TCB_PTR;                                                    \
        while (pNext != NULL && pNext->stackIndex >= 0)                        \
        {                                                                      \
            register sMT_TCB *pNext1;                                          \
            register int stackIndex;                                           \
            stackIndex = pNext->stackIndex;                                    \
            pNext->currentState = pNext->callStack[ stackIndex ].functionState;\
            pNext1 = (*pNext->callStack[ stackIndex ].pFunction)(pNext);       \
            MT_CLEAR_CALL( pNext );                                            \
            pNext = pNext1;                                                    \
        }                                                                      \
        return NULL;                                                           \
    }                                                                          \
}                                                                              


#define MT_RESUME_AT_TRAP(pTcb,pEnv,code)                                      \
{                                                                              \
    (pTcb)->stackIndex = (pEnv)->stackIndex;                                   \
    MT_PRINTF(pTcb,("MT_GOTO_TRAP, TCB=%08X, ENV=%08X", pTcb, pEnv));          \
    (pTcb)->currentState = (pEnv)->callBack.functionState;                     \
    (pTcb)->pTrappingFunction = (MT_FUNCTION_PTR)1;                            \
    (pTcb)->u.returnCode = code;                                               \
    if ( (*(pEnv)->callBack.pFunction)(pTcb) == NULL )                         \
    {                                                                          \
        /*return NULL;*/                                                       \
    }                                                                          \
    else                                                                       \
    {                                                                          \
        sMT_TCB *pNext;                                                        \
        pNext = pTcb;                                                          \
        while (pNext != NULL && pNext->stackIndex >= 0)                        \
        {                                                                      \
            register sMT_TCB *pNext1;                                          \
            register int stackIndex;                                           \
            stackIndex = pNext->stackIndex;                                    \
            pNext->currentState = pNext->callStack[ stackIndex ].functionState;\
            pNext1 = (*pNext->callStack[ stackIndex ].pFunction)(pNext);       \
            MT_CLEAR_CALL( pNext );                                            \
            pNext = pNext1;                                                    \
        }                                                                      \
        /*return NULL;*/                                                       \
    }                                                                          \
}



#define MT_IS_TRAP()                                                           \
    (MT_TCB_PTR)->pTrappingFunction                                            \
    

////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_GET_PARENT_STRUCT
//  Description:    Create a pointer to the IOB given a pointer to an embedded
//                  TCB
//  Returns:        none
//  Arguments:      iobType = the typedef for the IOB
//                  tcb     = the element name of the TCB which is embedded
//                            within the IOB
//  Notes:          This can only be used when the TCB is contained within the
//                  IOB.
//  
//                  typedef struct ITARG_IOB
//                  {
//                      int         something;
//                      sMT_TCB     tcb;
//                  } sITARG_IOB;
//
//                  pITARG_IOB pIob;
//                  
//                  pIob = MT_GET_PARENT_STRUCT(sITARG_IOB, tcb);
//
////////////////////////////////////////////////////////////////////////
#define MT_GET_PARENT_STRUCT(iobType, tcb)                                     \
    (iobType *)((char *)MT_TCB_PTR - offsetof(iobType, tcb))                   \


////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_SET_CONTEXT_PTR / MT_GET_CONTEXT_PTR
//  Description:    Save a context pointer in the TCB
//                  or Get the context pointer saved
//  Returns:        For SET, nothing
//                  For GET, the pointer which was saved by SET
//  Arguments:      For SET, the pointer to save
//                  For GET, the type of pointer that was saved
//  Notes:          
//
////////////////////////////////////////////////////////////////////////
#define MT_SET_CONTEXT_PTR(pTcb,ptr)                                           \
    (pTcb)->pContext = (void *)ptr


#define MT_GET_CONTEXT_PTR()                                                   \
    (MT_TCB_PTR)->pContext


#define MT_GET_CONTEXT_PTR_FROM_TCB(pTcb)                                      \
    (pTcb)->pContext


////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_SET_RETURN_CODE/MT_GET_RETURN_CODE
//  Description:    Set/Get the return code
//  Returns:        none
//  Arguments:      code = a code to be retrieved by MT_GET_RETURN_CODE
//  Notes:          The return code can also be set by MT_FINISHED.
//                  I make you give the TCB in the set function so you
//                  can supply a context (using the return code) for an 
//                  MT_RESUME operation.
//
////////////////////////////////////////////////////////////////////////
#define MT_SET_RETURN_CODE(tcb,code)                                           \
    (tcb)->u.returnCode = code                                                 \


#define MT_GET_RETURN_CODE()                                                   \
    (MT_TCB_PTR)->u.returnCode                                                 \


////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_SEM_INITIALIZE
//  Description:    Initialize a semaphore
//  Returns:        none
//  Arguments:      pSemaphore = a pointer to an MT_SEMAPHORE structure
//  Notes:          none
//
////////////////////////////////////////////////////////////////////////
#define MT_SEM_INITIALIZE(pSemaphore)                                          \
    {                                                                          \
        (pSemaphore)->signaled = 0;                                            \
    }                                                                          \


////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_SEM_WAIT
//  Description:    Wait on a semaphore
//  Returns:        none
//  Arguments:      pSemaphore = a pointer to an MT_SEMAPHORE structure
//                  callState = a state named by an MT_USE
//  Notes:          none
//
////////////////////////////////////////////////////////////////////////
#define MT_SEM_WAIT(pSemaphore,callState)                                      \
    {                                                                          \
        --(pSemaphore)->signaled;                                              \
        if ((pSemaphore)->signaled < 0)                                        \
        {                                                                      \
            (pSemaphore)->pTcb = MT_TCB_PTR;                                   \
            MT_SUSPEND(callState);                                             \
        }                                                                      \
    }                                                                          \


////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_SEM_SIGNAL
//  Description:    Signal a semaphore
//  Returns:        none
//  Arguments:      pSemaphore = a pointer to an MT_SEMAPHORE structure
//  Notes:          none
//
////////////////////////////////////////////////////////////////////////
#define MT_SEM_SIGNAL(pSemaphore)                                              \
    {                                                                          \
        ++(pSemaphore)->signaled;                                              \
        if ((pSemaphore)->signaled <= 0)                                       \
        {                                                                      \
            MT_RESUME((pSemaphore)->pTcb);                                     \
        }                                                                      \
    }                                                                          \


#endif  // ifdef __MT_CALL_H__
//#endif  // ifdef MT_MAX_DEPTH

////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_ABORT_THREAD
//  Description:    Aborts a thread that is suspended
//  Returns:        none
//  Arguments:      none
//  Notes:          If the thread is in execution, this cannot abort it.
//
//                  This will cause the MT_GOTO_TRAP routine to be called.
//                  The MT_GOTO_TRAP code MUST terminate. I.e., it can't do
//                  or lead up to an MT_SUSPEND and it can't do an MT_RETURN.
//
////////////////////////////////////////////////////////////////////////
#define MT_ABORT_THREAD(pTcb,pEnv,code)                                        \
    (pTcb)->stackIndex = (pEnv)->stackIndex;                                   \
    MT_PRINTF(pTcb,("MT_ABORT_THREAD, TCB=%08X, ENV=%08X, code=%08X", pTcb,    \
                                                               pEnv, code));   \
    (pTcb)->currentState = (pEnv)->callBack.functionState;                     \
    (pTcb)->pTrappingFunction = (MT_FUNCTION_PTR)1;                            \
    (pTcb)->u.returnCode = code;                                               \
    if ( (*(pEnv)->callBack.pFunction)(pTcb) == NULL )                         \
    {                                                                          \
        MT_ASSERT(!"MT_ABORT_THREAD didn't abort");                            \
    }


////////////////////////////////////////////////////////////////////////
//
//  Name:           MT_EXIT
//  Description:    Exit the thread. Something else will take over.
//  Returns:        none
//  Arguments:      none
//  Notes:          It is expected that something else will begin using
//                  the thread and take over control.
//
////////////////////////////////////////////////////////////////////////
#define MT_EXIT()                                                              \
    return NULL;

4 测试代码

#include <stddef.h>
#include <stdio.h>
#include <process.h>
#include <assert.h>

#define ASSERT assert
#define PRINTF printf
#define MT_ENTER_DEBUGGER() _asm { int 3 }

#define MT_DEBUG
#define MT_DEBUG_PRINT

#define MT_MAX_DEPTH        3
#define MT_STATES           \
    DO_SCAN,                \
    START_IO,               \
    TEST_UNIT_READY,        \
    CHECKING_DRIVE,         \
    GETTING_TYPE,           \
    TRAP_SCAN,             \
    EXECUTE_SCSI,           \
    WAIT_FOR_ITEM,          \
    FINISHED_NO_SUSPEND,    \
    FINISHED_WITH_SUSPEND,  \
    SUSPEND_THREAD
#define MT_TCB_PTR pTcb

#include "MtCall.h"

void main(void);
void Isr(void);

sMT_TCB CheckDevicesTcb;
sMT_ENVIRONMENT Environment;

typedef struct FUNNY_IOB
{
    int     something;
    sMT_TCB DetermineTypeTcb;
} sFUNNY_IOB, *pFUNNY_IOB;

sFUNNY_IOB DetermineTypeIob;

pMT_TCB pPendingTcb;
int     InterruptPending;

sMT_SEMAPHORE   Semaphore;

//#define TEST_NO_INTERRUPT_ON_IO
//#define TEST_INTERRUPT_IS_EARLY
//#define TEST_ASYNC_RESUME
//#define TEST_FINISH_FROM_CALL
#define TEST_TRAP_FROM_CALL
//#define TEST_TRAP_FROM_RESUME
#define MAX_DRIVES   1 

MT_FUNCTION (CheckDevicesThread);
MT_FUNCTION (DetermineTypeThread);
MT_FUNCTION (CheckDrive);
MT_FUNCTION (ExecuteScsi);
MT_FUNCTION (NoSuspendThread);
MT_FUNCTION (SuspendThread);

int DriveNum;

unsigned int *pItemToDo;
unsigned int *FirstItem;
unsigned int *SecondItem;


////////////////////////////////////////////////////////////////////////
//
//  Name:           StartIo
//  Description:    Simulate a start I/O
//  Returns:        1 if an interrupt is expected, 0 if not
//  Arguments:      none
//  Notes:          This will lead to an interrupt.
//
////////////////////////////////////////////////////////////////////////
int StartIo(sMT_TCB *pTcb)
{
    printf("Starting I/O\n");

    #ifdef TEST_NO_INTERRUPT_ON_IO
        return 0;
    #endif
        pPendingTcb = pTcb;
        InterruptPending = 1;
    #ifdef TEST_INTERRUPT_IS_EARLY
        Isr();
    #endif

    return 1;
}

////////////////////////////////////////////////////////////////////////
//
//  Name:           Isr
//  Description:    Simulate an ISR
//  Returns:        none
//  Arguments:      none
//  Notes:          
//
////////////////////////////////////////////////////////////////////////
void Isr(void)
{
    printf("Enter interrupt level\n");
    InterruptPending = 0;
    MT_RESUME(pPendingTcb);
    printf("Leave interrupt level\n");
}


////////////////////////////////////////////////////////////////////////
//
//  Name:           main
//  Description:    none
//  Returns:        none
//  Arguments:      none
//  Notes:          none
//
////////////////////////////////////////////////////////////////////////
void main(void)
{
    char ch;

    MT_SEM_INITIALIZE( &Semaphore );

    MT_START( &CheckDevicesTcb, CheckDevicesThread, NULL );

    SecondItem = NULL;
    FirstItem = (unsigned int *)&SecondItem;
    pItemToDo = (unsigned int *)&FirstItem;

    //  Test to be sure several signals in a row will work
    MT_SEM_SIGNAL( &Semaphore );
    MT_SEM_SIGNAL( &Semaphore );
    MT_SEM_SIGNAL( &Semaphore );

    #ifndef MT_USE_FUNCTIONS_DIRECTLY
        while (InterruptPending)
        {
            printf("Running some other task\n");
            Isr();
        }
    #endif

    if (CheckDevicesTcb.suspends != 0)
    {
        printf("**************Error, CheckDevicesTcb is still suspended\n");
    }
    else if (DetermineTypeIob.DetermineTypeTcb.suspends != 0)
    {
        printf("**************Error, DetermineTypeIob.DetermineTypeTcb is still"
               " suspended\n");
    }
    else
    {
        printf("All done.\n");
    }

    printf("Press Enter to exit ...");
    scanf_s("%c", &ch, 1);
    printf("\n");
}

////////////////////////////////////////////////////////////////////////
//
//  Name:           CheckDevicesThread
//  Description:    
//  Returns:        MT_FUNCTION
//  Arguments:      pTcb    = a pointer to the MT_TCB
//  Notes:          
//
////////////////////////////////////////////////////////////////////////
#undef MT_NAME
#define MT_NAME CheckDevicesThread
MT_FUNCTION (CheckDevicesThread)
{

    unsigned int *pItem;

    MT_ENTRY()
    {
        MT_USE( CHECKING_DRIVE );
        MT_USE( GETTING_TYPE );
        MT_USE( WAIT_FOR_ITEM );
        MT_USE( FINISHED_NO_SUSPEND );
//        MT_USE( FINISHED_WITH_SUSPEND );
    }

    //  Do this until the main code has no more items to do
    for (;;)
    {
        //  Wait until the main code has given us something to do via
        //  MT_SEM_SIGNAL
        MT_SEM_WAIT( &Semaphore, WAIT_FOR_ITEM );
        pItem = pItemToDo;
        if (pItem == NULL)
        {
            printf("pItem == NULL, nothing to do\n");
            break;
        }

        printf("Working on item %08X\n", pItem );
        pItemToDo = (unsigned int *)*pItemToDo;

        for (DriveNum = 0; DriveNum < MAX_DRIVES; DriveNum++)
        {
            //  Call a function that itself may make MT_CALLs
            MT_CALL(CheckDrive, CHECKING_DRIVE);
        }


        MT_START( &DetermineTypeIob.DetermineTypeTcb, NoSuspendThread,
           MT_TCB_PTR );
        MT_SUSPEND( FINISHED_NO_SUSPEND );
        
        // Start another thread
        MT_START( &DetermineTypeIob.DetermineTypeTcb, DetermineTypeThread,
           MT_TCB_PTR );
        
        // Suspend until the thread is done
        MT_SUSPEND( GETTING_TYPE );
        
        printf("Finished with DetermineTypeThread, rc=%d\n", 
           MT_GET_RETURN_CODE());
    }


    MT_RETURN( 0 );
    
}

#undef MT_NAME
#define MT_NAME NoSuspendThread
MT_FUNCTION (NoSuspendThread)
{
    
    MT_FINISHED(4321);
}

#undef MT_NAME
#define MT_NAME SuspendThread
MT_FUNCTION (SuspendThread)
{
    MT_ENTRY()
    {
        MT_USE( SUSPEND_THREAD );
    }

    MT_SUSPEND( SUSPEND_THREAD );
    MT_FINISHED(6789);
}

////////////////////////////////////////////////////////////////////////
//
//  Name:           DetermineTypeThread
//  Description:    
//  Returns:        MT_FUNCTION
//  Arguments:      implied by MT_TCB_PTR
//  Notes:          This is a new thread. It will resume the previous
//                  thread when it is done.
//
////////////////////////////////////////////////////////////////////////
#undef MT_NAME
#define MT_NAME DetermineTypeThread
MT_FUNCTION (DetermineTypeThread)
{
    pFUNNY_IOB pIob;

    pIob = MT_GET_PARENT_STRUCT( sFUNNY_IOB, DetermineTypeTcb);

    MT_ENTRY()
    {
        MT_USE( EXECUTE_SCSI );
    }

    #ifdef TEST_FINISH_FROM_CALL
        MT_FINISHED(4321);
    #endif

    //  Test to be sure nested MT_CALLs work
    MT_CALL( ExecuteScsi, EXECUTE_SCSI );

    //  This thread is finished
    MT_FINISHED(1234);

}

////////////////////////////////////////////////////////////////////////
//
//  Name:           CheckDrive
//  Description:    
//  Returns:        MT_FUNCTION
//  Arguments:      Implied by MT_TCB_PTR
//  Notes:
//
////////////////////////////////////////////////////////////////////////
#undef MT_NAME
#define MT_NAME CheckDrive
MT_FUNCTION (CheckDrive)
{
    MT_ENTRY()
    {
        MT_USE( TEST_UNIT_READY );
        #if defined(TEST_TRAP_FROM_CALL) || defined(TEST_TRAP_FROM_RESUME)
            MT_USE( TRAP_SCAN );
        #endif
    }

    #if defined(TEST_TRAP_FROM_CALL) || defined(TEST_TRAP_FROM_RESUME)
        MT_SET_CONTEXT_PTR( MT_TCB_PTR, &Environment );
        /* this is it */
        MT_SET_TRAP( &Environment, TRAP_SCAN );  
        if (MT_IS_TRAP())
        {
            printf("CheckDrive cought trap, rc=%d\n", MT_GET_RETURN_CODE());
            MT_RETURN( 0 );
        }
    #endif

    //  Test to be sure nested MT_CALLs work
    MT_CALL( ExecuteScsi, TEST_UNIT_READY );

    MT_RETURN( 0 );
}


////////////////////////////////////////////////////////////////////////
//
//  Name:           ExecuteScsi
//  Description:    
//  Returns:        MT_FUNCTION
//  Arguments:      Implied by MT_TCB_PTR
//  Notes:          
//
////////////////////////////////////////////////////////////////////////
#undef MT_NAME
#define MT_NAME ExecuteScsi
MT_FUNCTION (ExecuteScsi)
{
    MT_ENTRY()
    {
        MT_USE( START_IO );
    }

    #ifdef TEST_TRAP_FROM_CALL
        if (MT_GET_CONTEXT_PTR() != NULL)
        {
            printf("Traping in ExecuteScsi\n");
            MT_GOTO_TRAP((sMT_ENVIRONMENT *)MT_GET_CONTEXT_PTR(), 9876);
            printf("\n*************error, trap returned\n");
            exit(1);
        }
    #endif

    #ifdef TEST_ASYNC_RESUME
        {
            static int done;
            if (!done)
            {
                done = 1;
                MT_RESUME(  );
            }
        }
    #endif

    if (StartIo(pTcb))
    {
        MT_SUSPEND( START_IO );

        #ifdef TEST_TRAP_FROM_RESUME
            if (MT_GET_CONTEXT_PTR(pMT_ENV) != NULL)
            {
                printf("Traping in ExecuteScsi\n");
                MT_GOTO_TRAP(MT_GET_CONTEXT_PTR(sMT_ENVIRONMENT), 6789);
                printf("\n*************error, trap returned\n");
                exit(1);
            }
        #endif
    }

    MT_RETURN( 0 );
}

5 许可证

MT_CALL 是免费软件:您可以根据 The Code Project Open License (CPOL) 的条款重新分发和/或修改它,该许可证由 www.codeproject.com 发布(https://codeproject.org.cn/info/cpol10.aspx)。

MT_CALL 的分发希望它会有用,但不附带任何保证;甚至不附带适销性或特定用途适用性的默示保证。有关更多详细信息,请参阅 The Code Project Open License (CPOL),网址为 https://codeproject.org.cn/info/cpol10.aspx

© . All rights reserved.