Cyclers:

Shared Libraries (tine32.dll/tine64.dll libtinemt.so)
	-> n.b. tinemt.dll is identical to tine32.dll (32-bit build) or tine64.dll (64-bit build)
	-> interop with tine.dll (.NET dll build for 'AnyCPU') needs to find a tinemt.dll for its architecture)
	
=================================================
| windows: tine32.c ->  very windows specific ! |
=================================================

BOOL WINAPI DllMain(HINSTANCE hInstDll,DWORD fdwReason,LPVOID lpvReserved)
{
  char *ptr;
  lpvReserved = lpvReserved;
  switch (fdwReason)
  {
  case DLL_PROCESS_ATTACH:  /* DLL being loaded */
      gIsDynamicLoad = TRUE;
#     ifdef MULTITHREADED
      InitMutex(&hCyclerStartMutex);
      InitMutex(&hCyclerStopMutex);
      if ((ptr = getenv("TINE_DBG_PIPE")) != NULL) OpenIpcPipe(ptr);
#     else   /// Let's get rid of this #ifdef branch as we never build it this way ...
      {
        struct _timeb tb;
        _ftime(&tb);
        sprintf(gTineCycleWindowName, "TineCycle @ %hu:%hu", (int)tb.time, tb.millitm);
      }
#     endif
#     ifndef NO_TINE_PIPE
      hParent = hInstDll;
#     endif
      if ((ptr=getenv("TINE_START_CYCLER")) != NULL &&
           stricmp(ptr,"TRUE") == 0) SystemSetCycleTimer();  /// <<< or called via e.g. ACOP/CDI tbufsrv.dll etc.
      break;
    case DLL_THREAD_ATTACH:
      break;
    case DLL_THREAD_DETACH:
      break;
    case DLL_PROCESS_DETACH:  /* DLL being unloaded */
      if (lpvReserved)
      { // process is also terminating ...
	    /// <<<<< some discussion and disagreement with Davit Kalantaryn (Zeuthen) in 2020 
		/// <<<<< whether further cleanup is necessary if this is flag is 'true'
      }
      // no matter whether UnloadLibrary or process termination
      // we want to do the following ...
      feclog("library unloading");
      SetServerExitCondition(1); // make sure all the EQMs' exit routines are called
#     ifndef MULTITHREADED /// get rid of this! #ifndef as we never build it this way ...
      if (hTineCycleWnd != NULL)
      {
        DestroyWindow (hTineCycleWnd);
        UnregisterClass(gTineCycleWindowName,hParent);
      }
#     endif
      SystemKillCycleTimer(); // make sure any links close gracefully ...
      CloseClientMutexSet();
#     ifndef NO_TINE_PIPE
      hParent = 0;
#     endif
      break;
  }
  return (TRUE);
}


And here's the meat :

TINE_EXPORT void SystemStartCycleTimer(void)
{
  SystemSetCycleTimer();
}

TINE_EXPORT void SystemSetCycleTimer(void)
{
  SetServerExitCondition(0);
  InitSystemMutexSet();
  if (WaitForSystemMutex(hCyclerStopMutex,-1) != 0) 
  {
    feclog("SystemSetCycleTimer: stop local cycler mutex unavailable !");
    return;
  }
  if (cycleStarted) 
  {
    if (gIsRunningAsServer) feclog("attempt to start local cycler while it is still in use");
    goto err;
  }
  cycleStarted = TRUE;
  if (gIsRunningAsServer) feclog("starting local cycler");
# ifndef MULTITHREADED
  ...  // just get rid of this branch
# else
  if (gIsRunningAsServer) feclog("creating local cycler thread");
  UseMultiThreadedCycler(TRUE);
  hTmrThread = tmrCreateThread();  /// start that thread !!!!!!
  millisleep(gSystemDelay);
# endif
err:
  ReleaseSystemMutex(hCyclerStopMutex);
}

THREAD_TYPE tmrTaskThread(THREAD_PARAM lpvThreadParam)
{
  lpvThreadParam = lpvThreadParam;
  SetThreadName("CycleTask");
  if (WaitForSystemMutex(hCyclerStartMutex,-1) != 0)
  {
    feclog("tmrTaskThread: start local cycler mutex unavailable !");
    return semaphore_error;
  }
  feclog("timer thread starting");
  while (!cycleTerminated)
  { /* if nobody's at home then pause a bit to spare the CPU */
    if (!ServerInitialized && nConnectionTableEntries == 0) millisleep(gSystemDelay);
    /* run thru SystemCycle(): should block on select with timeout of gSystemDelay */
    srvTmrTask();  //// <<<< here's the SystemCycle() !!!!!
#   ifndef NO_TINE_PIPE
    if (!cycleTerminated) 
    { /* let windows do its thing ...    */
      DoEvents(50);
    }
#   endif
  }
  feclog("timer thread ending");
  feclog("flushing client and contract lists");
  flushContractTable();
  feclog("shutting down server ports");
  CloseServers(TRUE);
  FreeEQPModules();
  //SystemStop(FALSE);
  cycleStarted = FALSE;
  ReleaseSystemMutex(hCyclerStartMutex);
  return 0;
}

void srvTmrTask(void)
{
  if (cycleTerminated) return;
  if (cycle_busy++) return;
  SystemCycle(foregroundTTY);
  cycle_busy = 0;
  if (ServerExitCondition > 3) cycleTerminated = TRUE;
}

TINE_EXPORT void SystemKillCycleTimer(void)
{
  int cc = 0;
# ifdef MULTITHREADED
  DWORD threadExitCode;
# endif
  if (WaitForSystemMutex(hCyclerStopMutex,-1) != 0) 
  {
    feclog("SystemKillCycleTimer: stop local cycler mutex unavailable !");
    return;
  }
  if (!cycleStarted || cycleTerminated) 
  {
    if (!cycleTerminated) feclog("attempt to kill timer refused : local cycle not started");
    ReleaseSystemMutex(hCyclerStopMutex);
    return;
  }
  feclog("terminating local cycle");
  cycleTerminated = TRUE;
  CloseClientLinks();
# ifdef MULTITHREADED
  millisleep(gSystemDelay*2);
  if (cycleStarted)
  { /* cycle thread is still active ! */
    WaitForSingleObject(hTmrThread,2000);  //// absolute emergency cleanup !!!! << Davit did not like this part ...
    cc = GetExitCodeThread(hTmrThread,&threadExitCode);
    if (cc != 0 && threadExitCode == STILL_ACTIVE)
    { /* serious problem :  */
      feclog("force timer thread termination");
      cc = TerminateThread(hTmrThread,-1);
      cycleStarted = FALSE;
      feclog("shutting down server ports");
      CloseServers(TRUE);
      FreeEQPModules();
      freeUserCommands();
      ReleaseSystemMutex(hCyclerStartMutex); /* this, of course, probably won't work ! */
    }
    else
    {
      feclog("timer thread exited normally during wait");
    }
  }
  else
  {
    feclog("timer thread exited normally prior to wait");
  }
  /* n.b. AttachServer() calls SystemKillCycleTimer() -> can't close clients !!!! */
  if (!gIsRunningAsServer)
  {
#   ifdef TINE64_EXPORTS
    CloseClientsEx(TRUE, TRUE);
#   else
    CloseClients(TRUE);
#   endif
    CloseClientMutexSet();
  }

  if (hTmrThread != 0) 
  {
    feclog("closing timer thread handle");
    CloseHandle(hTmrThread);
  }
  hTmrThread = 0;
# endif
  feclog("closing system mutex set");
  CloseSystemMutexSet();
  ReleaseSystemMutex(hCyclerStopMutex);
# ifdef THIS_IS_NEEDED
  if (WaitForSystemMutex(hCyclerStartMutex,-1) != 0) 
  {
    return;
  }
  ReleaseSystemMutex(hCyclerStartMutex);
# endif
}

===========================================================
| unix/VxWorks: tcycler.c ->  'could' by used for windows |
===========================================================

/// instead of DLLMain :

#if defined(UNIX) && !defined(SOLARIS)
...
__attribute__((constructor)) void TineLoadCycler(void)
{
# ifndef TINE_NO_DYNAMIC_LOAD
  int startCycler = TINE_START_CYCLER;
  char *ptr = getenv("TINE_START_CYCLER");
  gIsDynamicLoad = TRUE;
  if (ptr != NULL)
  {
    startCycler = stricmp(ptr,"TRUE") == 0 ? TRUE : FALSE;
  }
  if (startCycler)
  { /* start cycler immediately */
    SystemSetCycleTimer();
  }
  else
  { /* let the app manage the cycling */
    InitCycleMutexSet();
  }
# endif
}
__attribute__((destructor)) void TineStopCyclerEpilog(void)
{
# ifndef TINE_NO_DYNAMIC_LOAD
  gIsClosingDynamic = TRUE;
  if (cycleTerminated) return;
  TineStopCycler();
  freeServerMemory();
# endif
}
#endif

THREAD_TYPE cycleTmrThread(THREAD_PARAM lpvThreadParam)
{
  lpvThreadParam = lpvThreadParam;

  SetThreadName("tcycler");
  if (WaitForSystemMutex(hCyclerStartMutex,-1) != 0) 
  {
    feclog("cycleTmrThread: start cycler mutex unavailable !");
    return 0;
  }
  UseMultiThreadedCycler(TRUE);
  while (!cycleTerminated)
  {
    cycleTmrTask();
  }
  cycleStarted = FALSE;
  CloseServers(TRUE);
  FreeEQPModules();
# ifdef UNIX
  pthread_detach(hTmrThread);
# endif
  hTmrThread = (THRHANDLE)0;
  gTmrThreadDetached = TRUE;
  ReleaseSystemMutex(hCyclerStartMutex);
  return 0;
}

TINE_EXPORT void killCycleTimer(void)
{
  if (WaitForSystemMutex(hCyclerStopMutex,-1) != 0) 
  {
    feclog("SystemKillCycleTimer: stop cycler mutex unavailable !");
    return;
  }
  if ((!cycleStarted && !gIsClosingDynamic) || cycleTerminated)
  {
    feclog("attempt to kill timer refused : cycle %s",cycleStarted ? "already terminated" : "not started");
    ReleaseSystemMutex(hCyclerStopMutex);
    return;
  }
  CloseClientLinks();
  cycleTerminated = TRUE; /* causes the cycle thread to stop => issues a SystemReset() */
  feclog("terminating local cycle");
  millisleep(gSystemDelay*2);
  ReleaseSystemMutex(hCyclerStopMutex);
  if (WaitForSystemMutex(hCyclerStartMutex,gSystemTick) != 0) 
  {
    return;
  }
  CloseClients(TRUE);
  CloseClientMutexSet();
  CloseSystemMutexSet();
  ReleaseSystemMutex(hCyclerStartMutex);
}

void SystemSetCycleTimer(void)
{
  int cc = 0;
  InitSystemMutexSet();
  InitCycleMutexSet();
  if (WaitForSystemMutex(hCyclerStopMutex,-1) != 0) 
  {
    if (gIsRunningAsServer) feclog("SystemSetCycleTimer: stop cycler mutex unavailable !");
    return;
  }
  if (cycleStarted) ccerr(-1);
  cycleStarted = TRUE;
  cycleInitTask(FALSE);
  hTmrThread = cycleCreateThread();
  millisleep(20);
err:
  UNUSED(cc);
  ReleaseSystemMutex(hCyclerStopMutex);
  return;
}
