📄 thread.cc
字号:
/* thread.cc: Locking and threading module functions Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. Originally written by Marco Fuykschot <marco@ddi.nl> Substantialy enhanced by Robert Collins <rbtcollins@hotmail.com>This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license. Please consult the file "CYGWIN_LICENSE" fordetails. *//* Implementation overview and caveats: Win32 puts some contraints on what can and cannot be implemented. Where possible we work around those contrainsts. Where we cannot work around the constraints we either pretend to be conformant, or return an error code. Some caveats: PROCESS_SHARED objects while they pretend to be process shared, may not actually work. Some test cases are needed to determine win32's behaviour. My suspicion is that the win32 handle needs to be opened with different flags for proper operation. R.Collins, April 2001. */#ifdef HAVE_CONFIG_H# include "config.h"#endif#ifdef _MT_SAFE#include "winsup.h"#include <limits.h>#include <errno.h>#include "cygerrno.h"#include <assert.h>#include <stdlib.h>#include <syslog.h>#include "pinfo.h"#include "perprocess.h"#include "security.h"#include <semaphore.h>#include <stdio.h>#include <sys/timeb.h>extern int threadsafe;struct _reent *_reent_clib (){ struct __reent_t *_r = (struct __reent_t *) MT_INTERFACE->reent_key.get ();#ifdef _CYG_THREAD_FAILSAFE if (_r == 0) system_printf ("local thread storage not inited");#endif return _r->_clib;}struct _winsup_t *_reent_winsup (){ struct __reent_t *_r = (struct __reent_t *) MT_INTERFACE->reent_key.get ();#ifdef _CYG_THREAD_FAILSAFE if (_r == 0) system_printf ("local thread storage not inited");#endif return _r->_winsup;}inline LPCRITICAL_SECTIONResourceLocks::Lock (int _resid){#ifdef _CYG_THREAD_FAILSAFE if (!inited) system_printf ("lock called before initialization"); thread_printf ("Get Resource lock %d ==> %p for %p , real : %d , threadid %d ", _resid, &lock, user_data, myself->pid, GetCurrentThreadId ());#endif return &lock;}voidSetResourceLock (int _res_id, int _mode, const char *_function){#ifdef _CYG_THREAD_FAILSAFE thread_printf ("Set resource lock %d mode %d for %s start", _res_id, _mode, _function);#endif EnterCriticalSection (user_data->resourcelocks->Lock (_res_id));#ifdef _CYG_THREAD_FAILSAFE user_data->resourcelocks->owner = GetCurrentThreadId (); user_data->resourcelocks->count++;#endif}voidReleaseResourceLock (int _res_id, int _mode, const char *_function){#ifdef _CYG_THREAD_FAILSAFE thread_printf ("Release resource lock %d mode %d for %s done", _res_id, _mode, _function); AssertResourceOwner (_res_id, _mode); user_data->resourcelocks->count--; if (user_data->resourcelocks->count == 0) user_data->resourcelocks->owner = 0;#endif LeaveCriticalSection (user_data->resourcelocks->Lock (_res_id));}#ifdef _CYG_THREAD_FAILSAFEvoidAssertResourceOwner (int _res_id, int _mode){ thread_printf ("Assert Resource lock %d ==> for %p , real : %d , threadid %d count %d owner %d", _res_id, user_data, myself->pid, GetCurrentThreadId (), user_data->resourcelocks->count, user_data->resourcelocks->owner); if (user_data && (user_data->resourcelocks->owner != GetCurrentThreadId ())) system_printf ("assertion failed, not the resource owner");}#endifvoidResourceLocks::Init (){ InitializeCriticalSection (&lock); inited = true;#ifdef _CYG_THREAD_FAILSAFE owner = 0; count = 0;#endif thread_printf ("lock %p inited by %p , %d", &lock, user_data, myself->pid);}voidResourceLocks::Delete (){ if (inited) { thread_printf ("Close Resource Locks %p ", &lock); DeleteCriticalSection (&lock); inited = false; }}voidMTinterface::Init (int forked){ reents._clib = _impure_ptr; reents._winsup = &winsup_reent; winsup_reent._process_logmask = LOG_UPTO (LOG_DEBUG); if (!forked) reent_key.set (&reents); pthread_mutex::initMutex ();}voidMTinterface::fixup_before_fork (void){ pthread_key::fixup_before_fork ();}/* This function is called from a single threaded process */voidMTinterface::fixup_after_fork (void){ pthread_key::fixup_after_fork (); pthread_mutex *mutex = mutexs; debug_printf ("mutexs is %x",mutexs); while (mutex) { mutex->fixup_after_fork (); mutex = mutex->next; } pthread_cond *cond = conds; debug_printf ("conds is %x",conds); while (cond) { cond->fixup_after_fork (); cond = cond->next; } semaphore *sem = semaphores; debug_printf ("semaphores is %x",semaphores); while (sem) { sem->fixup_after_fork (); sem = sem->next; } pthread::initMainThread (true); threadcount = 1;}/* pthread calls *//* static methods */voidpthread::initMainThread (bool do_init){ if (!do_init) return; pthread *thread = getTlsSelfPointer (); if (!thread) { thread = new pthread (); if (!thread) api_fatal ("failed to create mainthread object"); } thread->initCurrentThread ();}pthread *pthread::self (){ pthread *thread = getTlsSelfPointer (); if (thread) return thread; return pthreadNull::getNullpthread ();}voidpthread::setTlsSelfPointer (pthread *thisThread){ MT_INTERFACE->thread_self_key.set (thisThread);}pthread *pthread::getTlsSelfPointer (){ return (pthread *) MT_INTERFACE->thread_self_key.get ();}/* member methods */pthread::pthread ():verifyable_object (PTHREAD_MAGIC), win32_obj_id (0), cancelstate (0), canceltype (0), cancel_event (0), joiner (NULL), cleanup_stack (NULL){}pthread::~pthread (){ if (win32_obj_id) CloseHandle (win32_obj_id); if (cancel_event) CloseHandle (cancel_event);}voidpthread::setThreadIdtoCurrent (){ thread_id = GetCurrentThreadId ();}voidpthread::precreate (pthread_attr *newattr){ pthread_mutex *verifyable_mutex_obj = &mutex; /* already running ? */ if (win32_obj_id) return; if (newattr) { attr.joinable = newattr->joinable; attr.contentionscope = newattr->contentionscope; attr.inheritsched = newattr->inheritsched; attr.stacksize = newattr->stacksize; } if (!pthread_mutex::isGoodObject (&verifyable_mutex_obj)) { thread_printf ("New thread object access mutex is not valid. this %p", this); magic = 0; return; } cancel_event = ::CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); if (!cancel_event) { system_printf ("couldn't create cancel event, this %p LastError %E", this); /* we need the event for correct behaviour */ magic = 0; return; }}voidpthread::create (void *(*func) (void *), pthread_attr *newattr, void *threadarg){ precreate (newattr); if (!magic) return; function = func; arg = threadarg; win32_obj_id = ::CreateThread (&sec_none_nih, attr.stacksize, (LPTHREAD_START_ROUTINE) thread_init_wrapper, this, CREATE_SUSPENDED, &thread_id); if (!win32_obj_id) { thread_printf ("CreateThread failed: this %p LastError %E", this); magic = 0; } else { postcreate (); ResumeThread (win32_obj_id); }}voidpthread::postcreate (){ InterlockedIncrement (&MT_INTERFACE->threadcount); /* FIXME: set the priority appropriately for system contention scope */ if (attr.inheritsched == PTHREAD_EXPLICIT_SCHED) { /* FIXME: set the scheduling settings for the new thread */ /* sched_thread_setparam (win32_obj_id, attr.schedparam); */ }}voidpthread::exit (void *value_ptr){ class pthread *thread = this; // run cleanup handlers pop_all_cleanup_handlers (); pthread_key::runAllDestructors (); mutex.Lock (); // cleanup if thread is in detached state and not joined if (__pthread_equal (&joiner, &thread)) delete this; else { return_ptr = value_ptr; mutex.UnLock (); } if (InterlockedDecrement (&MT_INTERFACE->threadcount) == 0) ::exit (0); else ExitThread (0);}intpthread::cancel (void){ class pthread *thread = this; class pthread *self = pthread::self (); mutex.Lock (); if (canceltype == PTHREAD_CANCEL_DEFERRED || cancelstate == PTHREAD_CANCEL_DISABLE) { // cancel deferred mutex.UnLock (); SetEvent (cancel_event); return 0; } else if (__pthread_equal (&thread, &self)) { mutex.UnLock (); cancel_self (); return 0; // Never reached } // cancel asynchronous SuspendThread (win32_obj_id); if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT) { CONTEXT context; context.ContextFlags = CONTEXT_CONTROL; GetThreadContext (win32_obj_id, &context); context.Eip = (DWORD) pthread::static_cancel_self; SetThreadContext (win32_obj_id, &context); } mutex.UnLock (); ResumeThread (win32_obj_id); return 0;/* TODO: insert pthread_testcancel into the required functions the required function list is: *indicates done, X indicates not present in cygwin.aio_suspend ()*close ()*creat ()fcntl ()fsync ()getmsg ()getpmsg ()lockf ()mq_receive ()mq_send ()msgrcv ()msgsnd ()msync ()nanosleep ()open ()pause ()poll ()pread ()pthread_cond_timedwait ()pthread_cond_wait ()*pthread_join ()pthread_testcancel ()putmsg ()putpmsg ()pwrite ()read ()readv ()select ()sem_wait ()sigpause ()sigsuspend ()sigtimedwait ()sigwait ()sigwaitinfo ()*sleep ()system ()tcdrain ()*usleep ()wait ()wait3()waitid ()waitpid ()write ()writev ()the optional list is:catclose ()catgets ()catopen ()closedir ()closelog ()ctermid ()dbm_close ()dbm_delete ()dbm_fetch ()dbm_nextkey ()dbm_open ()dbm_store ()dlclose ()dlopen ()endgrent ()endpwent ()endutxent ()fclose ()fcntl ()fflush ()fgetc ()fgetpos ()fgets ()fgetwc ()fgetws ()fopen ()fprintf ()fputc ()fputs ()fputwc ()fputws ()fread ()freopen ()fscanf ()fseek ()fseeko ()fsetpos ()ftell ()ftello ()ftw ()fwprintf ()fwrite ()fwscanf ()getc ()getc_unlocked ()getchar ()getchar_unlocked ()getcwd ()getdate ()getgrent ()getgrgid ()getgrgid_r ()getgrnam ()getgrnam_r ()getlogin ()getlogin_r ()getpwent ()*getpwnam ()*getpwnam_r ()*getpwuid ()*getpwuid_r ()gets ()getutxent ()getutxid ()getutxline ()getw ()getwc ()getwchar ()getwd ()glob ()iconv_close ()iconv_open ()ioctl ()lseek ()mkstemp ()nftw ()opendir ()openlog ()pclose ()perror ()popen ()printf ()putc ()putc_unlocked ()putchar ()putchar_unlocked ()puts ()pututxline ()putw ()putwc ()putwchar ()readdir ()readdir_r ()remove ()rename ()rewind ()rewinddir ()scanf ()seekdir ()semop ()setgrent ()setpwent ()setutxent ()strerror ()syslog ()tmpfile ()tmpnam ()ttyname ()ttyname_r ()ungetc ()ungetwc ()unlink ()vfprintf ()vfwprintf ()vprintf ()vwprintf ()wprintf ()wscanf ()Note, that for fcntl (), for any value of the cmd argument.And we must not introduce cancellation points anywhere else that's part of the posix oropengroup specs. */}voidpthread::testcancel (void){ if (cancelstate == PTHREAD_CANCEL_DISABLE) return; if (WAIT_OBJECT_0 == WaitForSingleObject (cancel_event, 0)) cancel_self ();}voidpthread::static_cancel_self (void){ pthread::self ()->cancel_self ();}intpthread::setcancelstate (int state, int *oldstate){ int result = 0; mutex.Lock (); if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) result = EINVAL; else { if (oldstate) *oldstate = cancelstate; cancelstate = state; } mutex.UnLock (); return result;}intpthread::setcanceltype (int type, int *oldtype){ int result = 0; mutex.Lock (); if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) result = EINVAL; else { if (oldtype) *oldtype = canceltype; canceltype = type; } mutex.UnLock (); return result;}voidpthread::push_cleanup_handler (__pthread_cleanup_handler *handler){ if (this != self ()) // TODO: do it? api_fatal ("Attempt to push a cleanup handler across threads"); handler->next = cleanup_stack; InterlockedExchangePointer (&cleanup_stack, handler);}voidpthread::pop_cleanup_handler (int const execute){ if (this != self ()) // TODO: send a signal or something to the thread ? api_fatal ("Attempt to execute a cleanup handler across threads"); mutex.Lock ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -