Changeset 2787 for trunk


Ignore:
Timestamp:
Aug 27, 2006, 4:28:26 PM (19 years ago)
Author:
bird
Message:

Fixed problems with fork() and module loading/unloading. Fixes #76.
Fixed atexit() and on_exit() problem with callbacks in unloaded DLLs. Fixes #103.

Location:
trunk/libc
Files:
1 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/libc/ChangeLog.LIBC

    r2785 r2787  
    552006-08-27: knut st. osmundsen <bird-gccos2-spam@anduin.net>
    66    - libc:
     7        o Fixed problems with fork() and module loading/unloading. Fixes #76.
     8        o Fixed atexit() and on_exit() problem with callbacks in unloaded DLLs. Fixes #103.
    79        o Added usage counting to _CRT_init and _CRT_term. Fixing #114. (from 0.6)
    810        o Inlined _um_find_bucket. (from 0.6)
  • trunk/libc/include/InnoTekLIBC/atexit.h

    r1905 r2787  
    3737    __LIBC_ATEXITTYPE_ONEXIT,
    3838    /** State transition state. */
    39     __LIBC_ATEXITTYPE_TRANS
     39    __LIBC_ATEXITTYPE_TRANS,
     40    /** The module containing the callback was unloaded. */
     41    __LIBC_ATEXITTYPE_UNLOADED
    4042} __LIBC_ATEXITTYPE;
    4143
     
    4749    /** Entry type. */
    4850    __LIBC_ATEXITTYPE volatile enmType;
     51    /** The (native) module handle this callback is connected to.
     52     * This will be 0 if no such association. */
     53    uintptr_t                  hmod;
    4954    union
    5055    {
     
    9297 * @returns Pointer to new entry.
    9398 * @returns NULL on failure.
     99 *
     100 * @param   pvCallback      The callback address.
     101 *                          This used to initialize the __LIBC_AT_EXIT::hmod field.
    94102 */
    95 __LIBC_PATEXIT __libc_atexit_new(void);
     103__LIBC_PATEXIT __libc_atexit_new(void *pvCallback);
     104
     105/**
     106 * Invalidate all atexit and on_exit callback for a
     107 * module which is being unloaded.
     108 *
     109 * @param   hmod        The module handle.
     110 */
     111void __libc_atexit_unload(uintptr_t hmod);
    96112
    97113__END_DECLS
  • trunk/libc/include/InnoTekLIBC/fork.h

    r2320 r2787  
    575575/** Indicates that the module is an executable. */
    576576#define __LIBC_FORKMODULE_FLAGS_EXECUTABLE      0x00000001
    577 /** Indicates that the module was dynamically loaded. */
    578 #define __LIBC_FORKMODULE_FLAGS_DYNAMIC         0x00010000
     577/** Indicates that the module already has been deregistered (libc termination). */
     578#define __LIBC_FORKMODULE_FLAGS_DEREGISTERED    0x00010000
    579579/** @} */
    580580
     
    606606 */
    607607int __libc_ForkRegisterModule(__LIBC_PFORKMODULE pModule, int fExecutable);
     608
     609
     610/**
     611 * Deregister a forkable module. Called by dll0.
     612 *
     613 * The call links pModule out of the list of forkable modules
     614 * which is maintained in the process block.
     615 *
     616 * @param   pModule     Pointer to the fork module structure for the
     617 *                      module which is to registered.
     618 */
     619void __libc_ForkDeregisterModule(__LIBC_PFORKMODULE pModule);
    608620
    609621
  • trunk/libc/src/kNIX/os2/b_processWait.c

    r2732 r2787  
    4949#include <InnoTekLIBC/sharedpm.h>
    5050#include <InnoTekLIBC/backend.h>
    51 #include <klibc/fib.h>
     51#include <InnoTekLIBC/FastInfoBlocks.h>
    5252#include <InnoTekLIBC/fork.h>
    5353#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_BACK_PROCESS
     
    124124/** Number of known child processes. */
    125125static volatile unsigned    gcChildren;
    126 /** Total number of born child processes. */
     126/** Total number of born child processes. (For statistical purposes only.) */
    127127static volatile unsigned    gcBirths;
    128128/** Total number of died child processes. */
     
    171171         * Create the fmutex.
    172172         */
    173         _fmutex_checked_create(&gmtxWait, 0);
     173        _fmutex_checked_create2(&gmtxWait, _FMC_MUST_COMPLETE, "b_processWait.c: gmtxWait");
    174174        int rc = DosCreateEventSemEx(NULL, (PHEV)&ghevWait, 0, TRUE);
    175175        if (rc)
     
    194194void __libc_back_processWaitNotifyTerm(void)
    195195{
     196    __atomic_xchg(&gfTerminate, 1);
     197
     198    /* kill the thread - this is probably a waste of time in the exitlist handler... */
    196199    if (gtidThread)
    197200    {
    198         /* kill the thread - this is probably a waste of time in the exitlist handler... */
    199         __atomic_xchg(&gfTerminate, 1);
    200201        DosKillThread(gtidThread);
    201202        gtidThread = 0;
     
    223224     * Kill all known decendants.
    224225     */
     226    /** @todo We should really reparent them to the init process, but only the session manager can do that. */
    225227    PWAITCHILD pChild = gpChildrenHead;
    226228    if (pChild)
    227229    {
     230        gpChildrenHead = NULL;
     231        gcChildren = 0;
     232
    228233        /*
    229234         * Kill the process tree so we don't end up having childrens
     
    268273    int rc = _fmutex_request(&gmtxWait, fNoInterrupts ? _FMR_IGNINT : 0);
    269274    if (!rc)
    270     {
    271         ULONG cIgnore = 0;
    272         DosEnterMustComplete(&cIgnore);
    273275        return 0;
    274     }
    275276    LIBC_ASSERTM_FAILED("_fmutex_request -> %d\n", rc);
    276277    return -__libc_native2errno(rc);
     
    284285    int rc = _fmutex_release(&gmtxWait);
    285286    LIBC_ASSERTM(!rc, "_fmutex_release -> %d\n", rc);
    286     ULONG cIgnore = 0;
    287     DosExitMustComplete(&cIgnore);
    288287    rc = rc;
    289288}
     
    652651    if (!gtidThread)
    653652    {
     653        gfTerminate = 0;
     654
    654655        /*
    655656         * Create the internal thread for dealing with waiting.
  • trunk/libc/src/kNIX/os2/libcfork.c

    r2732 r2787  
    4747#include <InnoTekLIBC/fork.h>
    4848#include <InnoTekLIBC/sharedpm.h>
    49 #include <klibc/fib.h>
     49#include <InnoTekLIBC/FastInfoBlocks.h>
    5050#define __LIBC_LOG_GROUP    __LIBC_LOG_GRP_FORK
    5151#include <InnoTekLIBC/logstrict.h>
     
    314314
    315315    /*
    316      * Install exceptionhandler.
     316     * Install an exceptionhandler.
    317317     */
    318318    DosGetInfoBlocks(&pTib, &pPib);
     
    346346
    347347    /*
    348      * Check if dynamically loaded or not.
    349      */
    350     /** @todo! */
    351 
    352     /*
    353348     * Register the module.
    354      */
     349     * (We're hoping for OS/2 to indirectly serialize this... not properly verified yet.)
     350     */
     351    if (pModule->fFlags & __LIBC_FORKMODULE_FLAGS_DEREGISTERED)
     352        LIBCLOG_MSG("__LIBC_FORKMODULE_FLAGS_DEREGISTERED!\n");
     353    pModule->fFlags &= ~__LIBC_FORKMODULE_FLAGS_DEREGISTERED;
    355354    pModule->pNext = NULL;
    356355    if (pProcess->pvModuleHead)
     
    433432    pTib->tib_pexchain = XcptRegRec.prev_structure;
    434433    LIBCLOG_RETURN_INT(1);
     434}
     435
     436
     437/**
     438 * Deregister a forkable module. Called by dll0.
     439 *
     440 * The call links pModule out of the list of forkable modules
     441 * which is maintained in the process block.
     442 *
     443 * @param   pModule     Pointer to the fork module structure for the
     444 *                      module which is to registered.
     445 */
     446void __libc_ForkDeregisterModule(__LIBC_PFORKMODULE pModule)
     447{
     448    LIBCLOG_ENTER("pModule=%p:{.uVersion=%#x, .pfnAtFork=%p, .papParent1=%p, .papChild1=%p, .pvDataSegBase=%p, .pvDataSegEnd=%p, .fFlags=%#x, .pNext=%p}\n",
     449                  (void *)pModule, pModule->uVersion, (void *)pModule->pfnAtFork, (void *)pModule->papParent1, (void *)pModule->papChild1,
     450                  (void *)pModule->pvDataSegBase, (void *)pModule->pvDataSegEnd, pModule->fFlags, (void *)pModule->pNext);
     451
     452    /*
     453     * Don't deregister modules which has already been deregistered.
     454     * Don't deregister if we're in shutting down the process (waste of time and
     455     * SPM might already be shut down).
     456     */
     457    if (pModule->fFlags & __LIBC_FORKMODULE_FLAGS_DEREGISTERED)
     458        LIBCLOG_RETURN_MSG_VOID( "ret void (__LIBC_FORKMODULE_FLAGS_DEREGISTERD)\n");
     459    if (!__libc_GpFIBLIS)
     460        LIBCLOG_RETURN_MSG_VOID( "ret void (__libc_GpFIBLIS)\n");
     461    if (fibIsInExit())
     462        LIBCLOG_RETURN_MSG_VOID( "ret void (fibIsInExit)\n");
     463
     464    /*
     465     * Find the SPM process.
     466     */
     467    __LIBC_PSPMPROCESS pProcess = __libc_spmSelf();
     468    if (!pProcess)
     469    {
     470        LIBC_ASSERTM_FAILED("can't find the process! weird!\n");
     471        LIBCLOG_RETURN_VOID();
     472    }
     473
     474    /*
     475     * Deregister the module.
     476     * (We're hoping for OS/2 to indirectly serialize this... not properly verified yet.)
     477     */
     478    if ((__LIBC_PFORKMODULE)pProcess->pvModuleHead == pModule)
     479    {
     480        pProcess->pvModuleHead = pModule->pNext;
     481        if (!pModule->pNext)
     482            pProcess->ppvModuleTail = &pProcess->pvModuleHead;
     483    }
     484    else
     485    {
     486        __LIBC_PFORKMODULE pPrev = (__LIBC_PFORKMODULE)pProcess->pvModuleHead;
     487        while (pPrev && pPrev->pNext != pModule)
     488            pPrev = pPrev->pNext;
     489        if (!pPrev)
     490        {
     491            LIBC_ASSERTM_FAILED("can't find the module! weird!\n");
     492            LIBCLOG_RETURN_VOID();
     493        }
     494
     495        pPrev->pNext = pModule->pNext;
     496        if (!pModule->pNext)
     497            pProcess->ppvModuleTail = (void **)&pPrev->pNext;
     498    }
     499
     500    pModule->pNext = NULL;
     501    pModule->fFlags |= __LIBC_FORKMODULE_FLAGS_DEREGISTERED;
     502
     503    LIBCLOG_RETURN_VOID();
    435504}
    436505
     
    12801349    /*
    12811350     * Open and process the buffer on first call.
     1351     *
     1352     * Because of DosLoadModuleEx processing, we can end up here in while
     1353     * processing the initial fork buffer. This means that if any of those
     1354     * DLLS tries to talk to the parent at __LIBC_FORK_EXEC_CHILD time the
     1355     * fork() will fail. Fortunately, this is very unlikely. (Otherwise, we
     1356     * should've delayed those pfnAtFork() calls.)
    12821357     */
    12831358    if (pForkHandle->enmStage == __LIBC_FORK_STAGE_EXEC)
     
    12891364            LIBCLOG_RETURN_INT(rc);
    12901365        }
     1366        pForkHandle->enmStage = __LIBC_FORK_STAGE_INIT_CHILD;
    12911367        rc = forkBthBufferProcess(pForkHandle, __LIBC_FORK_CTX_CHILD, NULL);
    12921368        if (rc < 0)
     
    12951371            LIBCLOG_RETURN_INT(rc);
    12961372        }
    1297 
    1298         /* next stage */
    1299         pForkHandle->enmStage = __LIBC_FORK_STAGE_INIT_CHILD;
    13001373    }
    13011374
  • trunk/libc/src/libc/libc.def

    r2783 r2787  
    19531953    "__std_getdirents" @1951
    19541954    "___libc_Back_ioFileControlStandard" @1952
     1955    "___libc_Back_termDll" @1953
     1956    "___libc_ForkDeregisterModule" @1954
  • trunk/libc/src/libc/misc/atexit.c

    r2254 r2787  
    3030*******************************************************************************/
    3131#include "libc-alias.h"
     32#ifdef __OS2__
     33# define INCL_DOSMODULEMGR
     34# define INCL_ERRORS
     35# define INCL_FSMACROS
     36# include <os2emx.h>
     37#endif
    3238#include <stdlib.h>
    3339#include <InnoTekLIBC/atexit.h>
    34 #include <386/builtin.h>
     40#include <sys/builtin.h>
    3541#include <emx/umalloc.h>
    3642#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_INITTERM
     
    4147{
    4248    LIBCLOG_ENTER("pfnCallback=%p\n", (void *)pfnCallback);
    43     __LIBC_PATEXIT pCur = __libc_atexit_new();
     49    __LIBC_PATEXIT pCur = __libc_atexit_new((void *)pfnCallback);
    4450    if (pCur)
    4551    {
     
    5763 * @returns Pointer to new entry.
    5864 * @returns NULL on failure.
     65 *
     66 * @param   pvCallback      The callback address.
     67 *                          This used to initialize the __LIBC_AT_EXIT::hmod field.
    5968 */
    60 __LIBC_PATEXIT __libc_atexit_new(void)
     69__LIBC_PATEXIT __libc_atexit_new(void *pvCallback)
    6170{
     71    /*
     72     * Try find the module this callback belongs to.
     73 */
     74    uintptr_t   hmod = 0;
     75    /** @todo generalize DosQueryModFromEIP and let the (loader) backend do that kind of job. */
     76#ifdef __OS2__
     77    HMODULE     hmodOS2;
     78    ULONG       iObj, offObj;
     79    FS_VAR_SAVE_LOAD();
     80    APIRET rc = DosQueryModFromEIP(&hmodOS2, &iObj, 0, NULL, &offObj, (uintptr_t)pvCallback);
     81    if (rc == NO_ERROR)
     82        hmod = hmodOS2;
     83    FS_RESTORE();
     84#else
     85    /** @todo port to NT and other target platforms. */
     86#endif
     87
    6288    /*
    6389     * Search existing chunks.
     
    7298            if (__atomic_cmpxchg32(&pChunk->c, i + 1, i))
    7399            {
     100                pChunk->a[i].hmod = hmod;
    74101                pChunk->a[i].enmType = __LIBC_ATEXITTYPE_TRANS;
    75102                return &pChunk->a[i];
     
    84111    if (!pChunk)
    85112        return NULL;
     113    /** @todo There is a chance that the exit list order could be screwed up here if two threads get here at the same time. (bird, 2006-08-21) */
    86114    pChunk->c = 1;
     115    pChunk->a[0].hmod = hmod;
    87116    pChunk->a[0].enmType = __LIBC_ATEXITTYPE_TRANS;
    88117    do
     
    94123}
    95124
     125
     126/**
     127 * Invalidate all atexit and on_exit callback for a
     128 * module which is being unloaded.
     129 *
     130 * @param   hmod        The module handle.
     131 */
     132void __libc_atexit_unload(uintptr_t hmod)
     133{
     134    /*
     135     * Search existing chunks.
     136     * (This is made simple by us not freeing anything.)
     137     */
     138    __LIBC_PATEXITCHUNK pChunk;
     139    for (pChunk = __libc_gAtExitHead; pChunk; pChunk = pChunk->pNext)
     140    {
     141        uint32_t i = pChunk->c;
     142        while (i-- > 0)
     143        {
     144            if (    pChunk->a[i].hmod == hmod
     145                &&  pChunk->a[i].enmType > __LIBC_ATEXITTYPE_FREE
     146                &&  pChunk->a[i].enmType < __LIBC_ATEXITTYPE_TRANS)
     147                pChunk->a[i].enmType = __LIBC_ATEXITTYPE_UNLOADED;
     148        }
     149    }
     150}
     151
  • trunk/libc/src/libc/misc/on_exit.c

    r2254 r2787  
    44 * LIBC on_exit().
    55 *
    6  * Copyright (c) 2005 knut st. osmundsen <bird@anduin.net>
     6 * Copyright (c) 2005-2006 knut st. osmundsen <bird@anduin.net>
    77 *
    88 *
     
    3939{
    4040    LIBCLOG_ENTER("pfnCallback=%p pvUser=%p\n", (void *)pfnCallback, pvUser);
    41     __LIBC_PATEXIT pCur = __libc_atexit_new();
     41    __LIBC_PATEXIT pCur = __libc_atexit_new((void *)pfnCallback);
    4242    if (pCur)
    4343    {
  • trunk/libc/src/libc/startup/386/dll0.s

    r2289 r2787  
    5050#endif
    5151
     52#if defined(NOFORK)
     53#define FLAG_NOFORK     4
     54#else
     55#define FLAG_NOFORK     0
     56#endif
     57
     58    /*
     59     * The DLL Entry Point.
     60     */
    5261__text:
    5362    cmpl    $0, 8(%esp)
    54     jz      do_common_init
    55     jmp     do_initterm
     63    je      do_init
     64    cmpl    $1, 8(%esp)
     65    je      do_term
     66    jmp     _DLL_InitTerm
     67
    5668
    5769    /*
    58      * Nonstandard: we're doing some early initializations.
     70     * DLL Initialization.
    5971     */
    60 do_common_init:
     72do_init:
    6173#if !defined(NOFORK) && !defined(NOUNIX)
    6274    pushl   $0
     
    6577    addl    $8, %esp
    6678    cmpl    $0, %eax
    67     je      do_init
    68     jg      do_fork
    69 
    70     /* return failure (eax < 0). */
     79    je      do_init_not_forking
     80    jg      do_return_success   /* we're forking; no init. */
     81    /* else: eax < 0 - failure. */
     82do_return_failure:
    7183    xorl    %eax, %eax
    7284    ret
    73 
    74     /* return success - we're forking; no init. */
    75 do_fork:
     85do_return_success:
    7686    xorl    %eax, %eax
    7787    inc     %al
     
    7989
    8090    /* normal dll init. */
    81 do_init:
     91do_init_not_forking:
    8292#endif
     93    /* call __init_dll() */
    8394    pushl   4(%esp)
    84     pushl   $(FLAG_HIGHMEM + FLAG_NOUNIX)
     95    pushl   $(FLAG_HIGHMEM + FLAG_NOUNIX + FLAG_NOFORK)
    8596    call    ___init_dll
    8697    add     $8, %esp
    8798    orl     %eax, %eax
    88     jz      do_initterm
     99    jnz     do_return_failure
     100
     101    /* call _DLL_InitTerm */
     102    cld
     103    pushl   8(%esp)
     104    pushl   8(%esp)
     105    call    _DLL_InitTerm
     106    add     $8, %esp
     107    orl     %eax, %eax
     108    jnz     do_return_success
     109
     110    /* _DLL_InitTerm failed, undo the module registration. */
     111#if !defined(NOFORK) && !defined(NOUNIX)
     112    pushl   $ForkModule
     113    call    ___libc_ForkRegisterModule
     114    addl    $4, %esp
     115#endif
     116    jmp     do_return_failure;
     117
     118
    89119    /*
    90      * __init_dll() failed - fail the dll loading.
     120     * DLL Termination.
    91121     */
    92     xorl    %eax, %eax
     122do_term:
     123    /* do init term first */
     124    cld
     125    pushl   8(%esp)
     126    pushl   8(%esp)
     127    call    _DLL_InitTerm
     128    add     $8, %esp
     129    orl     %eax, %eax
     130    jnz     do_term_dll
    93131    ret
    94132
    95     /*
    96      * Standard initialization.
    97      */
    98 do_initterm:
    99     cld
    100     jmp     _DLL_InitTerm
     133do_term_dll:
     134    /* call __libc_Back_termDll() */
     135    pushl   4(%esp)
     136    pushl   $(FLAG_HIGHMEM + FLAG_NOUNIX + FLAG_NOFORK)
     137    call    ___libc_Back_termDll
     138    add     $8, %esp
     139
     140    /* call __libc_ForkDeregisterModule */
     141#if !defined(NOFORK) && !defined(NOUNIX)
     142    pushl   $ForkModule
     143    call    ___libc_ForkDeregisterModule
     144    addl    $4, %esp
     145#endif
     146    jmp     do_return_success
    101147
    102148
Note: See TracChangeset for help on using the changeset viewer.