Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ntthread.c   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "primpl.h"
#include <process.h> /* for _beginthreadex() */

/* --- globals ------------------------------------------------ */
PRLock* _pr_schedLock = NULL;
_PRInterruptTable _pr_interruptTable[] = {{0}};

BOOL _pr_use_static_tls = TRUE;
__declspec(thread) PRThread* _pr_current_fiber;
__declspec(thread) PRThread* _pr_fiber_last_run;
__declspec(thread) _PRCPU* _pr_current_cpu;
__declspec(thread) PRUintn _pr_ints_off;
DWORD _pr_currentFiberIndex;
DWORD _pr_lastFiberIndex;
DWORD _pr_currentCPUIndex;
DWORD _pr_intsOffIndex;

_MDLock _nt_idleLock;
PRCList _nt_idleList;
PRUint32 _nt_idleCount;

extern __declspec(thread) PRThread* _pr_io_restarted_io;
extern DWORD _pr_io_restartedIOIndex;

typedef HRESULT(WINAPI* SETTHREADDESCRIPTION)(HANDLE, PCWSTR);
static SETTHREADDESCRIPTION sSetThreadDescription = NULL;

/* Must check the restarted_io *before* decrementing no_sched to 0 */
#define POST_SWITCH_WORK()                                                    \
  PR_BEGIN_MACRO                                                              \
  PRThread* restarted_io =                                                    \
      (_pr_use_static_tls ? _pr_io_restarted_io                               \
                          : (PRThread*)TlsGetValue(_pr_io_restartedIOIndex)); \
  if (restarted_io) {                                                         \
    _nt_handle_restarted_io(restarted_io);                                    \
  }                                                                           \
  _PR_MD_LAST_THREAD()->no_sched = 0;                                         \
  PR_END_MACRO

void _nt_handle_restarted_io(PRThread* restarted_io) {
  /* After the switch we can resume an IO if needed.
   * XXXMB - this needs to be done in create thread, since that could
   * be the result for a context switch too..
   */

  PR_ASSERT(restarted_io->io_suspended == PR_TRUE);
  PR_ASSERT(restarted_io->md.thr_bound_cpu == restarted_io->cpu);

  _PR_THREAD_LOCK(restarted_io);
  if (restarted_io->io_pending == PR_FALSE) {
    /* The IO already completed, put us back on the runq. */
    int pri = restarted_io->priority;

    restarted_io->state = _PR_RUNNABLE;
    _PR_RUNQ_LOCK(restarted_io->cpu);
    _PR_ADD_RUNQ(restarted_io, restarted_io->cpu, pri);
    _PR_RUNQ_UNLOCK(restarted_io->cpu);
  } else {
    _PR_SLEEPQ_LOCK(restarted_io->cpu);
    _PR_ADD_SLEEPQ(restarted_io, restarted_io->sleep);
    _PR_SLEEPQ_UNLOCK(restarted_io->cpu);
  }
  restarted_io->io_suspended = PR_FALSE;
  restarted_io->md.thr_bound_cpu = NULL;

  _PR_THREAD_UNLOCK(restarted_io);

  if (_pr_use_static_tls) {
    _pr_io_restarted_io = NULL;
  } else {
    TlsSetValue(_pr_io_restartedIOIndex, NULL);
  }
}

void _PR_MD_EARLY_INIT() {
  HMODULE hModule;

  _MD_NEW_LOCK(&_nt_idleLock);
  _nt_idleCount = 0;
  PR_INIT_CLIST(&_nt_idleList);

#if 0
    /* Make the clock tick at least once per millisecond */
    if ( timeBeginPeriod(1) == TIMERR_NOCANDO) {
        /* deep yoghurt; clock doesn't tick fast enough! */
        PR_ASSERT(0);
    }
#endif

  if (!_pr_use_static_tls) {
    _pr_currentFiberIndex = TlsAlloc();
    _pr_lastFiberIndex = TlsAlloc();
    _pr_currentCPUIndex = TlsAlloc();
    _pr_intsOffIndex = TlsAlloc();
    _pr_io_restartedIOIndex = TlsAlloc();
  }

  // SetThreadDescription is Windows 10 build 1607+
  hModule = GetModuleHandleW(L"kernel32.dll");
  if (hModule) {
    sSetThreadDescription =
        (SETTHREADDESCRIPTION)GetProcAddress(hModule, "SetThreadDescription");
  }
}

void _PR_MD_CLEANUP_BEFORE_EXIT(void) {
  _PR_NT_FreeSids();

  WSACleanup();

  if (!_pr_use_static_tls) {
    TlsFree(_pr_currentFiberIndex);
    TlsFree(_pr_lastFiberIndex);
    TlsFree(_pr_currentCPUIndex);
    TlsFree(_pr_intsOffIndex);
    TlsFree(_pr_io_restartedIOIndex);
  }
}

PRStatus _PR_MD_INIT_THREAD(PRThread* thread) {
  thread->md.overlapped.ioModel = _MD_BlockingIO;
  thread->md.overlapped.data.mdThread = &thread->md;

  if (thread->flags & _PR_GLOBAL_SCOPE) {
    if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
      /*
      ** Warning:
      ** --------
      ** NSPR requires a real handle to every thread.
      ** GetCurrentThread() returns a pseudo-handle which
      ** is not suitable for some thread operations (e.g.,
      ** suspending).  Therefore, get a real handle from
      ** the pseudo handle via DuplicateHandle(...)
      */

      DuplicateHandle(GetCurrentProcess(),    /* Process of source handle */
                      GetCurrentThread(),     /* Pseudo Handle to dup */
                      GetCurrentProcess(),    /* Process of handle */
                      &(thread->md.handle),   /* resulting handle */
                      0L,                     /* access flags */
                      FALSE,                  /* Inheritable */
                      DUPLICATE_SAME_ACCESS); /* Options */
    }

    /* Create the blocking IO semaphore */
    thread->md.blocked_sema = CreateSemaphore(NULL, 0, 1, NULL);
    if (thread->md.blocked_sema == NULL) {
      return PR_FAILURE;
    }
    if (_native_threads_only) {
      /* Create the blocking IO semaphore */
      thread->md.thr_event = CreateEvent(NULL, TRUEFALSE, NULL);
      if (thread->md.thr_event == NULL) {
        return PR_FAILURE;
      }
    }
  }

  return PR_SUCCESS;
}

static unsigned __stdcall pr_root(void* arg) {
  PRThread* thread = (PRThread*)arg;
  thread->md.start(thread);
  return 0;
}

PRStatus _PR_MD_CREATE_THREAD(PRThread* thread, void (*start)(void*),
                              PRThreadPriority priority, PRThreadScope scope,
                              PRThreadState state, PRUint32 stackSize) {
  thread->md.start = start;
  thread->md.handle = (HANDLE)_beginthreadex(
      NULL, thread->stack->stackSize, pr_root, (void*)thread,
      CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, &(thread->id));
  if (!thread->md.handle) {
    PRErrorCode prerror;
    thread->md.fiber_last_error = GetLastError();
    switch (errno) {
      case ENOMEM:
        prerror = PR_OUT_OF_MEMORY_ERROR;
        break;
      case EAGAIN:
        prerror = PR_INSUFFICIENT_RESOURCES_ERROR;
        break;
      case EINVAL:
        prerror = PR_INVALID_ARGUMENT_ERROR;
        break;
      default:
        prerror = PR_UNKNOWN_ERROR;
    }
    PR_SetError(prerror, errno);
    return PR_FAILURE;
  }

  thread->md.id = thread->id;
  /*
   * On windows, a thread is created with a thread priority of
   * THREAD_PRIORITY_NORMAL.
   */

  if (priority != PR_PRIORITY_NORMAL) {
    _PR_MD_SET_PRIORITY(&(thread->md), priority);
  }

  /* Activate the thread */
  if (ResumeThread(thread->md.handle) != -1) {
    return PR_SUCCESS;
  }

  PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
  return PR_FAILURE;
}

void _PR_MD_JOIN_THREAD(_MDThread* md) {
  DWORD rv;

  rv = WaitForSingleObject(md->handle, INFINITE);
  PR_ASSERT(WAIT_OBJECT_0 == rv);
}

void _PR_MD_END_THREAD(void) { _endthreadex(0); }

void _PR_MD_YIELD(void) {
  /* Can NT really yield at all? */
  Sleep(0);
}

void _PR_MD_SET_PRIORITY(_MDThread* thread, PRThreadPriority newPri) {
  int nativePri;
  BOOL rv;

  if (newPri < PR_PRIORITY_FIRST) {
    newPri = PR_PRIORITY_FIRST;
  } else if (newPri > PR_PRIORITY_LAST) {
    newPri = PR_PRIORITY_LAST;
  }
  switch (newPri) {
    case PR_PRIORITY_LOW:
      nativePri = THREAD_PRIORITY_BELOW_NORMAL;
      break;
    case PR_PRIORITY_NORMAL:
      nativePri = THREAD_PRIORITY_NORMAL;
      break;
    case PR_PRIORITY_HIGH:
      nativePri = THREAD_PRIORITY_ABOVE_NORMAL;
      break;
    case PR_PRIORITY_URGENT:
      nativePri = THREAD_PRIORITY_HIGHEST;
  }
  rv = SetThreadPriority(thread->handle, nativePri);
  PR_ASSERT(rv);
  if (!rv) {
    PR_LOG(_pr_thread_lm, PR_LOG_MIN,
           ("PR_SetThreadPriority: can't set thread priority\n"));
  }
  return;
}

const DWORD MS_VC_EXCEPTION = 0x406D1388;

#pragma pack(push, 8)
typedef struct tagTHREADNAME_INFO {
  DWORD dwType;      // Must be 0x1000.
  LPCSTR szName;     // Pointer to name (in user addr space).
  DWORD dwThreadID;  // Thread ID (-1=caller thread).
  DWORD dwFlags;     // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)

void _PR_MD_SET_CURRENT_THREAD_NAME(const char* name) {
#ifdef _MSC_VER
  THREADNAME_INFO info;
#endif

  if (sSetThreadDescription) {
    WCHAR wideName[MAX_PATH];
    if (MultiByteToWideChar(CP_ACP, 0, name, -1, wideName, MAX_PATH)) {
      sSetThreadDescription(GetCurrentThread(), wideName);
    }
  }

#ifdef _MSC_VER
  if (!IsDebuggerPresent()) {
    return;
  }

  info.dwType = 0x1000;
  info.szName = (char*)name;
  info.dwThreadID = -1;
  info.dwFlags = 0;

  __try {
    RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR),
                   (ULONG_PTR*)&info);
  } __except (EXCEPTION_CONTINUE_EXECUTION) {
  }
#endif
}

void _PR_MD_CLEAN_THREAD(PRThread* thread) {
  BOOL rv;

  if (thread->md.acceptex_buf) {
    PR_DELETE(thread->md.acceptex_buf);
  }

  if (thread->md.xmit_bufs) {
    PR_DELETE(thread->md.xmit_bufs);
  }

  if (thread->md.blocked_sema) {
    rv = CloseHandle(thread->md.blocked_sema);
    PR_ASSERT(rv);
    thread->md.blocked_sema = 0;
  }
  if (_native_threads_only) {
    if (thread->md.thr_event) {
      rv = CloseHandle(thread->md.thr_event);
      PR_ASSERT(rv);
      thread->md.thr_event = 0;
    }
  }

  if (thread->md.handle) {
    rv = CloseHandle(thread->md.handle);
    PR_ASSERT(rv);
    thread->md.handle = 0;
  }

  /* Don't call DeleteFiber on current fiber or we'll kill the whole thread.
   * Don't call free(thread) until we've switched off the thread.
   * So put this fiber (or thread) on a list to be deleted by the idle
   * fiber next time we have a chance.
   */

  if (!(thread->flags & (_PR_ATTACHED | _PR_GLOBAL_SCOPE))) {
    _MD_LOCK(&_nt_idleLock);
    _nt_idleCount++;
    PR_APPEND_LINK(&thread->links, &_nt_idleList);
    _MD_UNLOCK(&_nt_idleLock);
  }
}

void _PR_MD_EXIT_THREAD(PRThread* thread) {
  BOOL rv;

  if (thread->md.acceptex_buf) {
    PR_DELETE(thread->md.acceptex_buf);
  }

  if (thread->md.xmit_bufs) {
    PR_DELETE(thread->md.xmit_bufs);
  }

  if (thread->md.blocked_sema) {
    rv = CloseHandle(thread->md.blocked_sema);
    PR_ASSERT(rv);
    thread->md.blocked_sema = 0;
  }

  if (_native_threads_only) {
    if (thread->md.thr_event) {
      rv = CloseHandle(thread->md.thr_event);
      PR_ASSERT(rv);
      thread->md.thr_event = 0;
    }
  }

  if (thread->md.handle) {
    rv = CloseHandle(thread->md.handle);
    PR_ASSERT(rv);
    thread->md.handle = 0;
  }

  if (thread->flags & _PR_GLOBAL_SCOPE) {
    _MD_SET_CURRENT_THREAD(NULL);
  }
}

void _PR_MD_EXIT(PRIntn status) { _exit(status); }

#ifdef HAVE_FIBERS

void _pr_fiber_mainline(void* unused) {
  PRThread* fiber = _PR_MD_CURRENT_THREAD();

  POST_SWITCH_WORK();

  fiber->md.fiber_fn(fiber->md.fiber_arg);
}

PRThread* _PR_MD_CREATE_USER_THREAD(PRUint32 stacksize, void (*start)(void*),
                                    void* arg) {
  PRThread* thread;

  if ((thread = PR_NEW(PRThread)) == NULL) {
    return NULL;
  }

  memset(thread, 0, sizeof(PRThread));
  thread->md.fiber_fn = start;
  thread->md.fiber_arg = arg;
  thread->md.fiber_stacksize = stacksize;
  return thread;
}

void _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(PRThread* thread) {
  thread->md.fiber_id = ConvertThreadToFiber(NULL);
  PR_ASSERT(thread->md.fiber_id);
  _MD_SET_CURRENT_THREAD(thread);
  _MD_SET_LAST_THREAD(thread);
  thread->no_sched = 1;
  return;
}

void _PR_MD_INIT_CONTEXT(PRThread* thread, char* top, void (*start)(void),
                         PRBool* status) {
  thread->md.fiber_fn = (void (*)(void*))start;
  thread->md.fiber_id =
      CreateFiber(thread->md.fiber_stacksize,
                  (LPFIBER_START_ROUTINE)_pr_fiber_mainline, NULL);
  if (thread->md.fiber_id != 0) {
    *status = PR_TRUE;
  } else {
    DWORD oserror = GetLastError();
    PRErrorCode prerror;
    if (oserror == ERROR_NOT_ENOUGH_MEMORY) {
      prerror = PR_OUT_OF_MEMORY_ERROR;
    } else {
      prerror = PR_UNKNOWN_ERROR;
    }
    PR_SetError(prerror, oserror);
    *status = PR_FALSE;
  }
}

void _PR_MD_SWITCH_CONTEXT(PRThread* thread) {
  PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));

  thread->md.fiber_last_error = GetLastError();
  _PR_Schedule();
}

void _PR_MD_RESTORE_CONTEXT(PRThread* thread) {
  PRThread* me = _PR_MD_CURRENT_THREAD();

  PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));

  /* The user-level code for yielding will happily add ourselves to the runq
   * and then switch to ourselves; the NT fibers can't handle switching to
   * ourselves.
   */

  if (thread != me) {
    SetLastError(thread->md.fiber_last_error);
    _MD_SET_CURRENT_THREAD(thread);
    _PR_MD_SET_LAST_THREAD(me);
    thread->no_sched = 1;
    SwitchToFiber(thread->md.fiber_id);
    POST_SWITCH_WORK();
  }
}

#endif /* HAVE_FIBERS */

PRInt32 _PR_MD_SETTHREADAFFINITYMASK(PRThread* thread, PRUint32 mask) {
  int rv;

  rv = SetThreadAffinityMask(thread->md.handle, mask);

  return rv ? 0 : -1;
}

PRInt32 _PR_MD_GETTHREADAFFINITYMASK(PRThread* thread, PRUint32* mask) {
  PRInt32 rv, system_mask;

  rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask);

  return rv ? 0 : -1;
}

void _PR_MD_SUSPEND_CPU(_PRCPU* cpu) { _PR_MD_SUSPEND_THREAD(cpu->thread); }

void _PR_MD_RESUME_CPU(_PRCPU* cpu) { _PR_MD_RESUME_THREAD(cpu->thread); }

void _PR_MD_SUSPEND_THREAD(PRThread* thread) {
  if (_PR_IS_NATIVE_THREAD(thread)) {
    /*
    ** There seems to be some doubt about whether or not SuspendThread
    ** is a synchronous function. The test afterwards is to help veriry
    ** that it is, which is what Microsoft says it is.
    */

    PRUintn rv = SuspendThread(thread->md.handle);
    PR_ASSERT(0xffffffffUL != rv);
  }
}

void _PR_MD_RESUME_THREAD(PRThread* thread) {
  if (_PR_IS_NATIVE_THREAD(thread)) {
    ResumeThread(thread->md.handle);
  }
}

PRThread* _MD_CURRENT_THREAD(void) {
  PRThread* thread;

  thread = _MD_GET_ATTACHED_THREAD();

  if (NULL == thread) {
    thread = _PRI_AttachThread(PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0);
  }
  PR_ASSERT(thread != NULL);
  return thread;
}

Messung V0.5
C=95 H=100 G=97

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge