none
Minimal UMS scheduler - Need help making it work RRS feed

  • Question

  • Hello,

    I'm playing with User Mode Scheduling, and I fail to make even a simple scheduler work.

    In the following code it chokes on ExecuteUmsThread returning "0x57 - invalid parameter"

    #define _WIN32_WINNT 0x0601 //Windows7
    #include <Windows.h>
    #include <malloc.h>
    #include <stdio.h>
    
    
    
    //YOU CAN COMPILE THIS SAMPLE USING FOLLOWING CMDLINE:
    //cl /MD /Zi test.cpp /link /SUBSYSTEM:CONSOLE /DEBUG
    
    //#define _debug_print(m)
    #define _debug_print(m) (g_MsgErrs[g_MsgIdx] = m, g_MsgIdx = (g_MsgIdx + 1) % _countof(g_MsgErrs))
    //#define _debug_print(m) OutputDebugStringA(m);
    //#define _debug_print(m) printf(m); // can deadlock
    
    #undef assert
    #define assert(_Expression) (void)( (!!(_Expression)) || (_debug_print( "ASSERTION : " #_Expression), __debugbreak(), 0) )
    
    
    char* g_MsgErrs[1024];
    int  g_MsgIdx = 0;
    PUMS_COMPLETION_LIST g_UMSCompletionList;
    PUMS_CONTEXT     g_pUmsThread;
    
    
    VOID __stdcall UmsSchedulerProc(UMS_SCHEDULER_REASON Reason, ULONG_PTR /*ActivationPayload*/, PVOID /*SchedulerParam*/)
    {
    
     switch (Reason)
     {
     case UmsSchedulerStartup:
      _debug_print("scheduler: starting task...\n");
      goto switch_to_task;
    
     case UmsSchedulerThreadYield:
      _debug_print("scheduler: task yielded...\n");
      goto switch_to_task;
     case UmsSchedulerThreadBlocked:
      
      _debug_print("scheduler: task blocked...\n");
    
      for (;;)
      {
       PUMS_CONTEXT UmsThreadList;
       if (DequeueUmsCompletionListItems(g_UMSCompletionList, 0, &UmsThreadList))
       {
        if (UmsThreadList)
        {
         assert(UmsThreadList == g_pUmsThread); // can't be anything else but our only task
    
         PUMS_CONTEXT next = GetNextUmsListItem(UmsThreadList);
         assert(next == NULL); // should have no more tasks
    
         ULONG retlen = 0;
         bool bTerminated = false;
         BOOL bOk = QueryUmsThreadInformation(g_pUmsThread, UmsThreadIsTerminated, &bTerminated, sizeof(bTerminated), &retlen);
         assert(bOk);
    
         if (bTerminated)
         {
          _debug_print("scheduler: task terminated...\n");
          return; // exit scheduling since our only task has finished
         }
    
         goto switch_to_task;
        }
       }
      }
     }
    
    switch_to_task:
     // start executing user task
     for (;;)
     {
      // switch to task
      ExecuteUmsThread(g_pUmsThread);
    
      // if we get here - task didn't start for some reason. Since we assume we are doing everything right, the only error possible here is ERROR_RETRY
      assert(GetLastError() == ERROR_RETRY);
     }
    }
    
    
    DWORD WINAPI UmsTaskProc(LPVOID /*lpThreadParameter*/)
    {
     printf("UMS Task has successfully started!");	
    
     UmsThreadYield(0);
    
     printf("Ums Task has successfully executed!");
    
     return 0;
    }
    
    extern "C" int __cdecl main()
    {
     BOOL bOk;
    
     //
     // create completion list
     //
     _debug_print("initializing completion list ...\n");
     bOk = CreateUmsCompletionList(&g_UMSCompletionList);
     assert(bOk);
    
    
     //
     // Creat Task (UMS Thread)
     //
     _debug_print("creating ums task...\n");
     SIZE_T attrsize = 0;
     InitializeProcThreadAttributeList(NULL, 1, 0, &attrsize);
      
     LPPROC_THREAD_ATTRIBUTE_LIST attrlist = (LPPROC_THREAD_ATTRIBUTE_LIST) _malloca(attrsize);
     memset(attrlist, 0, attrsize);
     bOk = InitializeProcThreadAttributeList(attrlist, 1, 0, &attrsize);
     assert(bOk);
    
     bOk = CreateUmsThreadContext(&g_pUmsThread);
     assert(bOk);
    
     UMS_CREATE_THREAD_ATTRIBUTES umsattribs = {UMS_VERSION, g_pUmsThread, g_UMSCompletionList};
     bOk = UpdateProcThreadAttribute(attrlist, 0, PROC_THREAD_ATTRIBUTE_UMS_THREAD, &umsattribs, sizeof(umsattribs), NULL, NULL);
     assert(bOk);
    
     HANDLE hThread = CreateRemoteThreadEx(GetCurrentProcess(), NULL, 0, &UmsTaskProc, 0, 0, attrlist, NULL);
     assert(hThread);
     CloseHandle(hThread);
    
     DeleteProcThreadAttributeList(attrlist);
     _freea(attrlist);
    
     
     //
     // Start scheduler
     //
     _debug_print("starting scheduler ...\n");
     UMS_SCHEDULER_STARTUP_INFO umsinfo = {UMS_VERSION, g_UMSCompletionList, UmsSchedulerProc, NULL};
     bOk = EnterUmsSchedulingMode(&umsinfo);
     assert(bOk);
     
     bOk = DeleteUmsThreadContext(g_pUmsThread);
     assert(bOk);
     
     return 0;
    }
    
    
    

    I also tried concrt sample with ums scheduler, but it bluescreens my win7 box.

    Thanks,

    Sergey.

     

    • Moved by Yi Feng Li Wednesday, April 21, 2010 3:43 AM related to SDK (From:Visual C++ General)
    Sunday, April 18, 2010 9:36 AM

Answers

  •  

    Hi SergeyN,

    Just 2 minor things in you code:

    1. In your UmsSchedulerStartup you must also wait for the UMS thread to show up in the completion list, not only in the UmsSchedulerThreadBlocked case. Threads are created asynchronously and you were trying to execute a UMS thread that is still not fully initialized. If you try to execute a thread in these conditions (the kernel is actually executing it) you will get this error;
    2. The correct type for bTerminated is BOOLEAN, not BOOL.

    So now this runs :)

     

    #define _WIN32_WINNT 0x0601 //Windows7
    #include <Windows.h>
    #include <malloc.h>
    #include <stdio.h>
    
    
    
    //YOU CAN COMPILE THIS SAMPLE USING FOLLOWING CMDLINE:
    //cl /MD /Zi test.cpp /link /SUBSYSTEM:CONSOLE /DEBUG
    
    //#define _debug_print(m)
    #define _debug_print(m) (g_MsgErrs[g_MsgIdx] = m, g_MsgIdx = (g_MsgIdx + 1) % _countof(g_MsgErrs))
    //#define _debug_print(m) OutputDebugStringA(m);
    //#define _debug_print(m) printf(m); // can deadlock
    
    #undef assert
    #define assert(_Expression) (void)( (!!(_Expression)) || (_debug_print( "ASSERTION : " #_Expression), __debugbreak(), 0) )
    
    
    char* g_MsgErrs[1024];
    int g_MsgIdx = 0;
    PUMS_COMPLETION_LIST g_UMSCompletionList;
    PUMS_CONTEXT   g_pUmsThread;
    
    
    VOID __stdcall UmsSchedulerProc(UMS_SCHEDULER_REASON Reason, ULONG_PTR ActivationPayload, PVOID SchedulerParam)
    {
    
     PUMS_CONTEXT next;
     ULONG retlen;
     BOOLEAN bTerminated;
     BOOL bOk;
    
     switch (Reason)
     {
     case UmsSchedulerStartup:
     _debug_print("scheduler: starting task...\n");
     break;
    
     case UmsSchedulerThreadYield:
     _debug_print("scheduler: task yielded...\n");
     goto switch_to_task;
    
     case UmsSchedulerThreadBlocked:
     _debug_print("scheduler: task blocked...\n");
     break;
     }
    
     for (;;)
     {
     PUMS_CONTEXT UmsThreadList;
     if (DequeueUmsCompletionListItems(g_UMSCompletionList, INFINITE, &UmsThreadList))
     {
      if (UmsThreadList)
      {
      assert(UmsThreadList == g_pUmsThread); // can't be anything else but our only task
      next = GetNextUmsListItem(UmsThreadList);
      assert(next == NULL); // should have no more tasks
      retlen = 0;
      bTerminated = FALSE;
      bOk = QueryUmsThreadInformation(g_pUmsThread, UmsThreadIsTerminated, &bTerminated, sizeof(bTerminated), &retlen);
      assert(bOk);
    
      if (bTerminated)
      {
       _debug_print("scheduler: task terminated...\n");
       return; // exit scheduling since our only task has finished
      }
    
      goto switch_to_task;
      }
     }
     }
    
    switch_to_task:
     // start executing user task
     for (;;)
     {
     // switch to task
     ExecuteUmsThread(g_pUmsThread);
    
     // if we get here - task didn't start for some reason. Since we assume we are doing everything right, the only error possible here is ERROR_RETRY
     assert(GetLastError() == ERROR_RETRY);
     }
    }
    
    
    DWORD WINAPI UmsTaskProc(LPVOID lpThreadParameter)
    {
     printf("UMS Task has successfully started!");  
    
     UmsThreadYield(0);
    
     printf("Ums Task has successfully executed!");
    
     return 0;
    }
    
    int __cdecl main()
    {
     BOOL bOk;
     SIZE_T attrsize;
     LPPROC_THREAD_ATTRIBUTE_LIST attrlist;
     UMS_CREATE_THREAD_ATTRIBUTES umsattribs;
     HANDLE hThread;
     UMS_SCHEDULER_STARTUP_INFO umsinfo;
    
     //
     // create completion list
     //
     _debug_print("initializing completion list ...\n");
     bOk = CreateUmsCompletionList(&g_UMSCompletionList);
     assert(bOk);
    
    
     //
     // Creat Task (UMS Thread)
     //
     _debug_print("creating ums task...\n");
     attrsize = 0;
     InitializeProcThreadAttributeList(NULL, 1, 0, &attrsize);
     
     attrlist = (LPPROC_THREAD_ATTRIBUTE_LIST) _malloca(attrsize);
     memset(attrlist, 0, attrsize);
     bOk = InitializeProcThreadAttributeList(attrlist, 1, 0, &attrsize);
     assert(bOk);
    
     bOk = CreateUmsThreadContext(&g_pUmsThread);
     assert(bOk);
    
     umsattribs.UmsVersion = UMS_VERSION;
     umsattribs.UmsContext = g_pUmsThread;
     umsattribs.UmsCompletionList = g_UMSCompletionList;
     bOk = UpdateProcThreadAttribute(attrlist, 0, PROC_THREAD_ATTRIBUTE_UMS_THREAD, &umsattribs, sizeof(umsattribs), NULL, NULL);
     assert(bOk);
    
     hThread = CreateRemoteThreadEx(GetCurrentProcess(), NULL, 0, &UmsTaskProc, 0, 0, attrlist, NULL);
     assert(hThread);
     CloseHandle(hThread);
    
     DeleteProcThreadAttributeList(attrlist);
     _freea(attrlist);
    
     
     //
     // Start scheduler
     //
     _debug_print("starting scheduler ...\n");
     umsinfo.UmsVersion = UMS_VERSION;
     umsinfo.CompletionList = g_UMSCompletionList;
     umsinfo.SchedulerProc = UmsSchedulerProc;
     umsinfo.SchedulerParam = NULL;
     
     bOk = EnterUmsSchedulingMode(&umsinfo);
     assert(bOk);
     
     bOk = DeleteUmsThreadContext(g_pUmsThread);
     assert(bOk);
     
     return 0;
    }

     

    Cheers!

    Pedro Teixeira


    PedroT
    Wednesday, April 21, 2010 11:18 PM

All replies

  • Guys,

    Maybe someone can point me to another forum were I might get some help ?

     

    Thanks,

    Sergey.

    Tuesday, April 20, 2010 6:53 AM
  • Hi SergayN

     

    I am moving this thread from Base “Visual C++ General" forum to the “Windows SDK” forum, since the issue is related to Windows SDK. There are more experts in the “Windows SDK" forum.

     

     

    Cheers

    Yi Feng Li


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Wednesday, April 21, 2010 3:42 AM
  • Thanks,

    Hopefully I'll get help here.

     

    Sergey.

    Wednesday, April 21, 2010 8:53 AM
  •  

    Hi SergeyN,

    Just 2 minor things in you code:

    1. In your UmsSchedulerStartup you must also wait for the UMS thread to show up in the completion list, not only in the UmsSchedulerThreadBlocked case. Threads are created asynchronously and you were trying to execute a UMS thread that is still not fully initialized. If you try to execute a thread in these conditions (the kernel is actually executing it) you will get this error;
    2. The correct type for bTerminated is BOOLEAN, not BOOL.

    So now this runs :)

     

    #define _WIN32_WINNT 0x0601 //Windows7
    #include <Windows.h>
    #include <malloc.h>
    #include <stdio.h>
    
    
    
    //YOU CAN COMPILE THIS SAMPLE USING FOLLOWING CMDLINE:
    //cl /MD /Zi test.cpp /link /SUBSYSTEM:CONSOLE /DEBUG
    
    //#define _debug_print(m)
    #define _debug_print(m) (g_MsgErrs[g_MsgIdx] = m, g_MsgIdx = (g_MsgIdx + 1) % _countof(g_MsgErrs))
    //#define _debug_print(m) OutputDebugStringA(m);
    //#define _debug_print(m) printf(m); // can deadlock
    
    #undef assert
    #define assert(_Expression) (void)( (!!(_Expression)) || (_debug_print( "ASSERTION : " #_Expression), __debugbreak(), 0) )
    
    
    char* g_MsgErrs[1024];
    int g_MsgIdx = 0;
    PUMS_COMPLETION_LIST g_UMSCompletionList;
    PUMS_CONTEXT   g_pUmsThread;
    
    
    VOID __stdcall UmsSchedulerProc(UMS_SCHEDULER_REASON Reason, ULONG_PTR ActivationPayload, PVOID SchedulerParam)
    {
    
     PUMS_CONTEXT next;
     ULONG retlen;
     BOOLEAN bTerminated;
     BOOL bOk;
    
     switch (Reason)
     {
     case UmsSchedulerStartup:
     _debug_print("scheduler: starting task...\n");
     break;
    
     case UmsSchedulerThreadYield:
     _debug_print("scheduler: task yielded...\n");
     goto switch_to_task;
    
     case UmsSchedulerThreadBlocked:
     _debug_print("scheduler: task blocked...\n");
     break;
     }
    
     for (;;)
     {
     PUMS_CONTEXT UmsThreadList;
     if (DequeueUmsCompletionListItems(g_UMSCompletionList, INFINITE, &UmsThreadList))
     {
      if (UmsThreadList)
      {
      assert(UmsThreadList == g_pUmsThread); // can't be anything else but our only task
      next = GetNextUmsListItem(UmsThreadList);
      assert(next == NULL); // should have no more tasks
      retlen = 0;
      bTerminated = FALSE;
      bOk = QueryUmsThreadInformation(g_pUmsThread, UmsThreadIsTerminated, &bTerminated, sizeof(bTerminated), &retlen);
      assert(bOk);
    
      if (bTerminated)
      {
       _debug_print("scheduler: task terminated...\n");
       return; // exit scheduling since our only task has finished
      }
    
      goto switch_to_task;
      }
     }
     }
    
    switch_to_task:
     // start executing user task
     for (;;)
     {
     // switch to task
     ExecuteUmsThread(g_pUmsThread);
    
     // if we get here - task didn't start for some reason. Since we assume we are doing everything right, the only error possible here is ERROR_RETRY
     assert(GetLastError() == ERROR_RETRY);
     }
    }
    
    
    DWORD WINAPI UmsTaskProc(LPVOID lpThreadParameter)
    {
     printf("UMS Task has successfully started!");  
    
     UmsThreadYield(0);
    
     printf("Ums Task has successfully executed!");
    
     return 0;
    }
    
    int __cdecl main()
    {
     BOOL bOk;
     SIZE_T attrsize;
     LPPROC_THREAD_ATTRIBUTE_LIST attrlist;
     UMS_CREATE_THREAD_ATTRIBUTES umsattribs;
     HANDLE hThread;
     UMS_SCHEDULER_STARTUP_INFO umsinfo;
    
     //
     // create completion list
     //
     _debug_print("initializing completion list ...\n");
     bOk = CreateUmsCompletionList(&g_UMSCompletionList);
     assert(bOk);
    
    
     //
     // Creat Task (UMS Thread)
     //
     _debug_print("creating ums task...\n");
     attrsize = 0;
     InitializeProcThreadAttributeList(NULL, 1, 0, &attrsize);
     
     attrlist = (LPPROC_THREAD_ATTRIBUTE_LIST) _malloca(attrsize);
     memset(attrlist, 0, attrsize);
     bOk = InitializeProcThreadAttributeList(attrlist, 1, 0, &attrsize);
     assert(bOk);
    
     bOk = CreateUmsThreadContext(&g_pUmsThread);
     assert(bOk);
    
     umsattribs.UmsVersion = UMS_VERSION;
     umsattribs.UmsContext = g_pUmsThread;
     umsattribs.UmsCompletionList = g_UMSCompletionList;
     bOk = UpdateProcThreadAttribute(attrlist, 0, PROC_THREAD_ATTRIBUTE_UMS_THREAD, &umsattribs, sizeof(umsattribs), NULL, NULL);
     assert(bOk);
    
     hThread = CreateRemoteThreadEx(GetCurrentProcess(), NULL, 0, &UmsTaskProc, 0, 0, attrlist, NULL);
     assert(hThread);
     CloseHandle(hThread);
    
     DeleteProcThreadAttributeList(attrlist);
     _freea(attrlist);
    
     
     //
     // Start scheduler
     //
     _debug_print("starting scheduler ...\n");
     umsinfo.UmsVersion = UMS_VERSION;
     umsinfo.CompletionList = g_UMSCompletionList;
     umsinfo.SchedulerProc = UmsSchedulerProc;
     umsinfo.SchedulerParam = NULL;
     
     bOk = EnterUmsSchedulingMode(&umsinfo);
     assert(bOk);
     
     bOk = DeleteUmsThreadContext(g_pUmsThread);
     assert(bOk);
     
     return 0;
    }

     

    Cheers!

    Pedro Teixeira


    PedroT
    Wednesday, April 21, 2010 11:18 PM
  • Hello Pedro,

     

    Thanks again for your answer. I am also wondering if you know what exactly ums win7 rtm issue concrt is trying to handle with ResourceManager::RequireUMSWorkaround() function ?

     

    Thanks,

    Sergey.

    Thursday, April 22, 2010 6:36 PM
  • Hello all,

       I'm wondering whether UmsSchedulerProc function is called in thread safe manner if we have multiple UMS threads?



    Thursday, April 28, 2011 10:17 PM