LINUX.ORG.RU

gcc под виндой - 2


0

2

Продолжаю портировать/переделывать одну dll с msvc++ на gcc. Возник тут интересный затык связанный с тем что вызов _beginthreadex он не из WinAPI, а из CRT, и помимо старта нового треда делает копирование глобальных статических переменных сишного рантайма в TLS. Есть ли в GCC/mingw аналог этого вызова? Я так понимаю что список глобальных статических переменных у каждой реализации CRT свой, и поэтому реализация _beginthreadex у gcc должна быть своя?

★★★

Мне кажется это заморочки реализации конкретного рантайма и тебе стоит на них забить. И да, CreateThread все еще отлично работает - не понятно в чем практическая разница.

Pavval ★★★★★
()
Ответ на: комментарий от Pavval

>И да, CreateThread все еще отлично работает - не понятно в чем практическая разница.

Ну вообще-то если бы библиотека была написана на чистом Си, я бы забил и юзал CreateThread. Но в портируемой либе довольно экстенсивно юзаются фичи С++, а они часто приклеплены к глобальным переменным в неожиданных и удивительных местах.

Absurd ★★★
() автор топика
Ответ на: комментарий от Absurd

Ну вообще-то если бы библиотека была написана на чистом Си, я бы забил и юзал CreateThread. Но в портируемой либе довольно экстенсивно юзаются фичи С++, а они часто приклеплены к глобальным переменным в неожиданных и удивительных местах.

Эмм... Видел не один проект на msvc++ с CreateThread - все нормально работало. Можно подробности?

Pavval ★★★★★
()
Ответ на: комментарий от Pavval

>Видел не один проект на msvc++ с CreateThread - все нормально работало. Можно подробности?

Первое что приходит на ум - локальные статические переменные. AFAIK они инициализируются как-то с применением барьеров. А их деструкторы регистрируются через глобальный статический массив, доступ к которому тоже должен быть синхронизирован.

Absurd ★★★
() автор топика
Ответ на: комментарий от Absurd

да никаких там барьеров нет за синхру отвечает разраб а деструктоы вообще в одном потоке вызываются последними так эта исходники же есть рантайма она там инит потоко специфичные фичи типа errno strtok float point ну и подобную хрень вообщем шушара

anonymous
()
Ответ на: комментарий от Absurd

Ну а что мешает делать инициализацию ondemand? Вызвали рантайм из нового потока и он обнаружил, что его TLS не инициализарован. Взял и сделал это. А синхронизация это не проблема: создай в главном потоке все необходимые объекты синхронизации и пользуй их с любых потоков.

Pavval ★★★★★
()
Ответ на: комментарий от Absurd

пижжю пижжю

struct ololo
{
	ololo(){}
	~ololo(){}
};

int main(int argc, char *argv[])
{
	static ololo subj;
}
	static ololo subj;
0041128E A1 24 81 41 00   mov         eax,dword ptr [$S1 (418124h)] 
00411293 83 E0 01         and         eax,1 
00411296 75 32            jne         main+5Ah (4112CAh) 
00411298 A1 24 81 41 00   mov         eax,dword ptr [$S1 (418124h)] 
0041129D 83 C8 01         or          eax,1 
004112A0 A3 24 81 41 00   mov         dword ptr [$S1 (418124h)],eax 
004112A5 C7 45 FC 00 00 00 00 mov         dword ptr [ebp-4],0 
004112AC B9 20 81 41 00   mov         ecx,offset subj (418120h) 
004112B1 E8 6C FE FF FF   call        ololo::ololo (411122h) 
004112B6 68 70 41 41 00   push        offset `main'::`2'::`dynamic atexit destructor for 'subj'' (414170h) 
004112BB E8 81 FD FF FF   call        @ILT+60(_atexit) (411041h) 
004112C0 83 C4 04         add         esp,4 
за конструктор отвечает разраб синхра и прочая на нем а atexit сама лочит доступ к глобальному массиву при добавлении указателя вот такую хрень генерирует компиль для каждого статик объекта ее адрес сует в массив а она уже дергает деструктор
`main'::`2'::`dynamic atexit destructor for 'subj'':
00414170 55               push        ebp  
00414171 8B EC            mov         ebp,esp 
00414173 83 EC 40         sub         esp,40h 
00414176 53               push        ebx  
00414177 56               push        esi  
00414178 57               push        edi  
00414179 B9 20 81 41 00   mov         ecx,offset subj (418120h) 
0041417E E8 13 CF FF FF   call        ololo::~ololo (411096h) 
00414183 5F               pop         edi  
00414184 5E               pop         esi  
00414185 5B               pop         ebx  
00414186 8B E5            mov         esp,ebp 
00414188 5D               pop         ebp  
00414189 C3               ret              

anonymous
()
Ответ на: комментарий от Absurd

а вот atexit

_onexit_t __cdecl _onexit (
        _onexit_t func
        )
{
        _onexit_t retval;

        _lockexit();

        __try {
            retval = _onexit_nolock(func);
        }
        __finally {
            _unlockexit();
        }

        return retval;
}
первый слой ставит лок на доступ к массиву с указателями на трамплины которые вызывают деструкторы а потом добавляет указатель ня
static _onexit_t __cdecl _onexit_nolock (
        _onexit_t func
        )
{
        _PVFV * p;
        size_t  oldsize;
        _PVFV * onexitbegin = (_PVFV *)_decode_pointer(__onexitbegin);
        _PVFV * onexitend = (_PVFV *)_decode_pointer(__onexitend);

        /* overflow check */
        if (onexitend < onexitbegin ||
            ((char *)onexitend - (char *)onexitbegin) + sizeof(_PVFV) < sizeof(_PVFV))
        {
            return NULL;
        }

        /*
         * First, make sure the table has room for a new entry
         */
        if ( (oldsize = _msize_crt(onexitbegin))
                < ((size_t)((char *)onexitend -
            (char *)onexitbegin) + sizeof(_PVFV)) )
        {
            /*
             * not enough room, try to grow the table. first, try to double it.
             */
            size_t newsize = oldsize + __min(oldsize, (MAXINCR * sizeof(_PVFV)));
            if ( newsize < oldsize ||
                 (p = (_PVFV *)_realloc_crt(onexitbegin, newsize)) == NULL )
            {
                /*
                 * failed, try to grow by MININCR
                 */
                newsize = oldsize + MININCR * sizeof(_PVFV);
                if ( newsize < oldsize ||
                     (p = (_PVFV *)_realloc_crt(onexitbegin, newsize)) == NULL )
                    /*
                     * failed again. don't do anything rash, just fail
                     */
                    return NULL;
            }

            /*
             * update __onexitend and __onexitbegin
             */
#pragma warning(suppress: 22008) /* prefast is confused */
            onexitend = p + (onexitend - onexitbegin);
            onexitbegin = p;
            __onexitbegin = (_PVFV *)_encode_pointer(onexitbegin);
        }

        /*
         * Put the new entry into the table and update the end-of-table
         * pointer.
         */
         *(onexitend++) = (_PVFV)_encode_pointer(func);
        __onexitend = (_PVFV *)_encode_pointer(onexitend);

        return func;
}

anonymous
()
Ответ на: комментарий от Pavval

>Ну а что мешает делать инициализацию ondemand?

Меня беспокоит STL и iostream(там самопальная сериализация через iostream сделана). Они тоже могут быть привязаны какими-нибудь неожиданными соплями к глобальным статическим объектам. Насколько я помню, в msvc++ при добавлении ключика /MT реализация рантайма менялась очень ощутимо.

Absurd ★★★
() автор топика
Ответ на: комментарий от Absurd

Насколько я помню, в msvc++ при добавлении ключика /MT реализация рантайма менялась очень ощутимо.

Там просто использовался другой рантайм.

Нашел в сорцах mingw:

/*
 * The functions _beginthreadex and _endthreadex are not provided by CRTDLL.
 * They are provided by MSVCRT.
 *
 * NOTE: Apparently _endthread calls CloseHandle on the handle of the thread,
 * making for race conditions if you are not careful. Basically you have to
 * make sure that no-one is going to do *anything* with the thread handle
 * after the thread calls _endthread or returns from the thread function.
 *
 * NOTE: No old names for these functions. Use the underscore.
 */
_CRTIMP unsigned long __cdecl __MINGW_NOTHROW
	_beginthread	(void (*)(void *), unsigned, void*);
_CRTIMP void __cdecl __MINGW_NOTHROW _endthread	(void);

#ifdef	__MSVCRT__
_CRTIMP unsigned long __cdecl __MINGW_NOTHROW
	_beginthreadex	(void *, unsigned, unsigned (__stdcall *) (void *), 
			 void*, unsigned, unsigned*);
_CRTIMP void __cdecl __MINGW_NOTHROW _endthreadex (unsigned);
#endif

Т.е. если ты собираешь с MSVCRT, то у тебя есть _beginthreadex и _endthreadex, а если с родным рантаймом, то только _beginthread и _endthread.

Pavval ★★★★★
()
Ответ на: комментарий от Absurd

нет мелкософт специально вырезал обработку ексепшенов из исходников црт все все остальное есть ну цэшный рантпайм по ним запросто состряпать

anonymous
()

include/process.h, mingw один из последних

/*
 * The functions _beginthreadex and _endthreadex are not provided by CRTDLL.
 * They are provided by MSVCRT.
 *
 * NOTE: Apparently _endthread calls CloseHandle on the handle of the thread,
 * making for race conditions if you are not careful. Basically you have to
 * make sure that no-one is going to do *anything* with the thread handle
 * after the thread calls _endthread or returns from the thread function.
 *
 * NOTE: No old names for these functions. Use the underscore.
 */
_CRTIMP unsigned long __cdecl __MINGW_NOTHROW
	_beginthread	(void (*)(void *), unsigned, void*);
_CRTIMP void __cdecl __MINGW_NOTHROW _endthread	(void);

#ifdef	__MSVCRT__
_CRTIMP unsigned long __cdecl __MINGW_NOTHROW
	_beginthreadex	(void *, unsigned, unsigned (__stdcall *) (void *), 
			 void*, unsigned, unsigned*);
_CRTIMP void __cdecl __MINGW_NOTHROW _endthreadex (unsigned);
#endif

т.е. они там как бы уже есть...

xydo ★★
()
Ответ на: комментарий от Pavval

>Т.е. если ты собираешь с MSVCRT, то у тебя есть _beginthreadex и _endthreadex, а если с родным рантаймом, то только _beginthread и _endthread.

О! Наконец-то начался конструктивный разговор. Я тоже этот кусок кода видел. Теперь вопрос:

А что такое «собирать с MSVCRT»? Там надо какой-то ключик добавить в компилятор и линкер?

Absurd ★★★
() автор топика
Ответ на: комментарий от Absurd

Попробуй просто задать __MSVCRT__ и линковать с ним.

Pavval ★★★★★
()
Ответ на: комментарий от Absurd

вот эта структура крепится к каждому потоку тут в основном всякая хрень относящаяся к немногопоточным си функциям

/* Structure for each thread's data */

struct _tiddata {
    unsigned long   _tid;       /* thread ID */


    uintptr_t _thandle;         /* thread handle */

    int     _terrno;            /* errno value */
    unsigned long   _tdoserrno; /* _doserrno value */
    unsigned int    _fpds;      /* Floating Point data segment */
    unsigned long   _holdrand;  /* rand() seed value */
    char *      _token;         /* ptr to strtok() token */
    wchar_t *   _wtoken;        /* ptr to wcstok() token */
    unsigned char * _mtoken;    /* ptr to _mbstok() token */

    /* following pointers get malloc'd at runtime */
    char *      _errmsg;        /* ptr to strerror()/_strerror() buff */
    wchar_t *   _werrmsg;       /* ptr to _wcserror()/__wcserror() buff */
    char *      _namebuf0;      /* ptr to tmpnam() buffer */
    wchar_t *   _wnamebuf0;     /* ptr to _wtmpnam() buffer */
    char *      _namebuf1;      /* ptr to tmpfile() buffer */
    wchar_t *   _wnamebuf1;     /* ptr to _wtmpfile() buffer */
    char *      _asctimebuf;    /* ptr to asctime() buffer */
    wchar_t *   _wasctimebuf;   /* ptr to _wasctime() buffer */
    void *      _gmtimebuf;     /* ptr to gmtime() structure */
    char *      _cvtbuf;        /* ptr to ecvt()/fcvt buffer */
    unsigned char _con_ch_buf[MB_LEN_MAX];
                                /* ptr to putch() buffer */
    unsigned short _ch_buf_used;   /* if the _con_ch_buf is used */

    /* following fields are needed by _beginthread code */
    void *      _initaddr;      /* initial user thread address */
    void *      _initarg;       /* initial user thread argument */

    /* following three fields are needed to support signal handling and
     * runtime errors */
    void *      _pxcptacttab;   /* ptr to exception-action table */
    void *      _tpxcptinfoptrs; /* ptr to exception info pointers */
    int         _tfpecode;      /* float point exception code */

    /* pointer to the copy of the multibyte character information used by
     * the thread */
    pthreadmbcinfo  ptmbcinfo;

    /* pointer to the copy of the locale informaton used by the thead */
    pthreadlocinfo  ptlocinfo;
    int         _ownlocale;     /* if 1, this thread owns its own locale */

    /* following field is needed by NLG routines */
    unsigned long   _NLG_dwCode;

    /*
     * Per-Thread data needed by C++ Exception Handling
     */
    void *      _terminate;     /* terminate() routine */
    void *      _unexpected;    /* unexpected() routine */
    void *      _translator;    /* S.E. translator */
    void *      _purecall;      /* called when pure virtual happens */
    void *      _curexception;  /* current exception */
    void *      _curcontext;    /* current exception context */
    int         _ProcessingThrow; /* for uncaught_exception */
    void *              _curexcspec;    /* for handling exceptions thrown from std::unexpected */
#if defined (_M_IA64) || defined (_M_AMD64)
    void *      _pExitContext;
    void *      _pUnwindContext;
    void *      _pFrameInfoChain;
    unsigned __int64    _ImageBase;
#if defined (_M_IA64)
    unsigned __int64    _TargetGp;
#endif  /* defined (_M_IA64) */
    unsigned __int64    _ThrowImageBase;
    void *      _pForeignException;
#elif defined (_M_IX86)
    void *      _pFrameInfoChain;
#endif  /* defined (_M_IX86) */
    _setloc_struct _setloc_data;

#ifdef _M_IX86
    void *      _encode_ptr;    /* EncodePointer() routine */
    void *      _decode_ptr;    /* DecodePointer() routine */
#endif  /* _M_IX86 */

    };

typedef struct _tiddata * _ptiddata;

anonymous
()
Ответ на: комментарий от Pavval
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.