在vs2008下使用cygwin(22):使用tls

来源:互联网 发布:byte数组合并 编辑:程序博客网 时间:2024/05/16 09:09

 

快乐虾

http://blog.csdn.net/lights_joy/

lights@hb165.com

  

本文适用于

Cygwin-1.16

Vs2008

  

欢迎转载,但请保留作者信息

 

cygwin为了支持多线程,使用了tls,关于这一部分的实现,其文档是这样解释的:

All cygwin threads have separate context in an object of class _cygtls.  The

storage for this object is kept on the stack in the bottom CYGTLS_PADSIZE

bytes.  Each thread references the storage via the Thread Environment Block

(aka Thread Information Block), which Windows maintains for each user thread

in the system, with the address in the FS segment register.  The memory

is laid out as in the NT_TIB structure from <w32api/winnt.h>:

 

typedef struct _NT_TIB {

     struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;

     PVOID StackBase;

     PVOID StackLimit;

     PVOID SubSystemTib;

     _ANONYMOUS_UNION union {

         PVOID FiberData;

         DWORD Version;

     } DUMMYUNIONNAME;

     PVOID ArbitraryUserPointer;

     struct _NT_TIB *Self;

} NT_TIB,*PNT_TIB;

 

Cygwin sees it like this:

 

extern exception_list *_except_list asm ("%fs:0");      // exceptions.cc

extern char *_tlsbase __asm__ ("%fs:4");                // cygtls.h

extern char *_tlstop __asm__ ("%fs:8");                 // cygtls.h

 

And accesses cygtls like this:

 

#define _my_tls (((_cygtls *) _tlsbase)[-1])            // cygtls.h

 

 

Initialization always goes through _cygtls::init_thread().  It works

in the following ways:

 

* In the main thread, _dll_crt0() provides CYGTLS_PADSIZE bytes on the stack

  and passes them to initialize_main_tls(), which calls _cygtls::init_thread().

  It then calls dll_crt0_1(), which terminates with cygwin_exit() rather than

  by returning, so the storage never goes out of scope.

 

  If you load cygwin1.dll dynamically from a non-cygwin application, it is

  vital that the bottom CYGTLS_PADSIZE bytes of the stack are not in use

  before you call cygwin_dll_init().  See winsup/testsuite/cygload for

  more information.

 

* Threads other than the main thread receive DLL_THREAD_ATTACH messages

  to dll_entry() (in init.cc).

  - dll_entry() calls munge_threadfunc(), which grabs the function pointer

    for the thread from the stack frame and substitutes threadfunc_fe(),

  - which then passes the original function pointer to _cygtls::call(),

  - which then allocates CYGTLS_PADSIZE bytes on the stack and hands them

    to call2(),

  - which allocates an exception_list object on the stack and hands it to

    init_exceptions() (in exceptions.cc), which attaches it to the end of

    the list of exception handlers, changing _except_list (aka

    tib->ExceptionList), then passes the cygtls storage to init_thread().

    call2() calls ExitThread() instead of returning, so the storage never

    goes out of scope.

 

Note that the padding isn't necessarily going to be just where the _cygtls

structure lives; it just makes sure there's enough room on the stack when the

CYGTLS_PADSIZE bytes down from there are overwritten.

所有依赖于tls的全局变量都必须从_tlsbase这个指针开始计算,它的定义在cygtls.h中:

extern char *_tlsbase __asm__ ("%fs:4");

但在vs2008下并不支持这样的定义,为此不得不另寻它法。最简单的莫过于借助CThreadLocal,这是mfc中的一个类,但实际上我们只需要使用mfc中的afxtls.cppafxtls_.h两个文件。

CNoTrackObject继承一个类:

class CCygTlsData : public CNoTrackObject

{

public: // 定义cygwin里的全局变量

     ……………..

};

EXTERN_THREAD_LOCAL(CCygTlsData, cyg_global_data);

所有全局变量都通过cyg_global_data获取即可。

 

 

 

参考资料

vs2008下使用cygwin1):前言(2008-10-16)

vs2008下使用cygwin2):i686-pc-cygwin/newlib/Makefile分析(2008-10-16)

vs2008下使用cygwin3):i686-pc-cygwin/newlib/libc/Makefile分析(2008-10-16)

vs2008下使用cygwin4):i686-pc-cygwin/newlib/libc/argz/Makefile分析(2008-10-16)

vs2008下使用cygwin5):i686-pc-cygwin/newlib/libc/stdlib/Makefile分析(2008-10-16)

vs2008下使用cygwin6):i686-pc-cygwin/newlib/libc/ctype/Makefile分析(2008-10-16)

vs2008下使用cygwin7):i686-pc-cygwin/newlib/libc/search/Makefile分析(2008-10-16)

vs2008下使用cygwin8):i686-pc-cygwin/newlib/libc/stdio/Makefile分析(2008-10-16)

vs2008下使用cygwin9):i686-pc-cygwin/newlib/libc/stdio64/Makefile分析(2008-10-16)

vs2008下使用cygwin10):i686-pc-cygwin/newlib/libc/string/Makefile分析 (2008-10-16)

vs2008下使用cygwin11):i686-pc-cygwin/newlib/libc/signal/Makefile分析 (2008-10-16)

vs2008下使用cygwin12):i686-pc-cygwin/newlib/libc/time/Makefile分析 (2008-10-16)

vs2008下使用cygwin13):i686-pc-cygwin/newlib/libc/locale/Makefile分析 (2008-10-16)

vs2008下使用cygwin14):i686-pc-cygwin/newlib/libc/reent/Makefile分析 (2008-10-16)

vs2008下使用cygwin15):i686-pc-cygwin/newlib/libc/misc/Makefile分析 (2008-10-16)

vs2008下使用cygwin16):i686-pc-cygwin/newlib/libc/machine/i386/Makefile分析 (2008-10-16)

vs2008下使用cygwin17):i686-pc-cygwin/newlib/libc/posix/Makefile分析 (2008-10-16)

vs2008下使用cygwin18):i686-pc-cygwin/newlib/libc/syscalls/Makefile分析 (2008-10-16)

vs2008下使用cygwin19):i686-pc-cygwin/newlib/libm/Makefile分析(2008-10-17)

vs2008下使用cygwin20):i686-pc-cygwin/newlib/libm/math/Makefile分析2008-10-17

vs2008下使用cygwin21):i686-pc-cygwin/newlib/libm/common/Makefile分析(2008-10-17)