VirtualBox

Changeset 3460 in kBuild for trunk/src/kash/shinstance.c


Ignore:
Timestamp:
Sep 15, 2020 12:31:01 PM (5 years ago)
Author:
bird
Message:

kash: Use event semaphores to signal parent shell early before the subshell thread has performed cleanups.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kash/shinstance.c

    r3459 r3460  
    7373/** Mutex serializing exec/spawn to prevent unwanted file inherting. */
    7474shmtx               g_sh_exec_inherit_mtx;
     75/** Mutex protecting g_sh_sts_free. */
     76static shmtx        g_sh_sts_mtx;
     77/** List of free subshell status structure (saves CreateEvent calls).  */
     78static shsubshellstatus * volatile g_sh_sts_free = NULL;
    7579#endif
    7680/** The mutex protecting the the globals and some shell instance members (sigs). */
     
    708712#ifndef SH_FORKED_MODE
    709713    shmtx_init(&g_sh_exec_inherit_mtx);
     714    shmtx_init(&g_sh_sts_mtx);
    710715#endif
    711716
     
    14151420}
    14161421
     1422#ifndef SH_FORKED_MODE
     1423
     1424/**
     1425 * Retains a reference to a subshell status structure.
     1426 */
     1427static unsigned shsubshellstatus_retain(shsubshellstatus *sts)
     1428{
     1429    unsigned refs = sh_atomic_dec(&sts->refs);
     1430    assert(refs > 1);
     1431    assert(refs < 16);
     1432    return refs;
     1433}
     1434
     1435/**
     1436 * Releases a reference to a subshell status structure.
     1437 */
     1438static unsigned shsubshellstatus_release(shinstance *psh, shsubshellstatus *sts)
     1439{
     1440    unsigned refs = sh_atomic_dec(&sts->refs);
     1441    assert(refs < ~(unsigned)0/4);
     1442    if (refs == 0)
     1443    {
     1444        shmtxtmp tmp;
     1445        shmtx_enter(&g_sh_sts_mtx, &tmp);
     1446        sts->next = g_sh_sts_free;
     1447        g_sh_sts_free = sts;
     1448        shmtx_leave(&g_sh_sts_mtx, &tmp);
     1449    }
     1450    return refs;
     1451}
     1452
     1453/**
     1454 * Creates a subshell status structure.
     1455 */
     1456static shsubshellstatus *shsubshellstatus_create(shinstance *psh, int refs)
     1457{
     1458    shsubshellstatus *sts;
     1459
     1460    /* Check the free list: */
     1461    if (g_sh_sts_free)
     1462    {
     1463        shmtxtmp tmp;
     1464        shmtx_enter(&g_sh_sts_mtx, &tmp);
     1465        sts = g_sh_sts_free;
     1466        if (sts)
     1467            g_sh_sts_free = sts->next;
     1468        shmtx_leave(&g_sh_sts_mtx, &tmp);
     1469    }
     1470    else
     1471        sts = NULL;
     1472    if (sts)
     1473    {
     1474# if K_OS == K_OS_WINDOWS
     1475        BOOL rc = ResetEvent((HANDLE)sts->towaiton);
     1476        assert(rc); K_NOREF(rc);
     1477# endif
     1478    }
     1479    else
     1480    {
     1481        /* Create a new one: */
     1482        sts = (shsubshellstatus *)sh_malloc(psh, sizeof(*sts));
     1483        if (!sts)
     1484            return NULL;
     1485# if K_OS == K_OS_WINDOWS
     1486        sts->towaiton = (void *)CreateEventW(NULL /*noinherit*/, TRUE /*fManualReset*/,
     1487                                             FALSE /*fInitialState*/, NULL /*pszName*/);
     1488        if (!sts->towaiton)
     1489        {
     1490            assert(0);
     1491            sh_free(psh, sts);
     1492            return NULL;
     1493        }
     1494# endif
     1495    }
     1496
     1497    /* Initialize it: */
     1498    sts->refs     = refs;
     1499    sts->status   = 999999;
     1500    sts->done     = 0;
     1501    sts->next     = NULL;
     1502# if K_OS == K_OS_WINDOWS
     1503    sts->hThread  = 0;
     1504# endif
     1505    return sts;
     1506}
     1507
     1508#endif /* !SH_FORKED_MODE */
     1509
    14171510/**
    14181511 * Adds a child to the shell
     
    14221515 * @param   psh         The shell instance.
    14231516 * @param   pid         The child pid.
    1424  * @param   hChild      Windows child handle.
    1425  * @param   fProcess    Set if process, clear if thread.
     1517 * @param   hChild      Windows child wait handle (process if sts is NULL).
     1518 * @param   sts         Subshell status structure, NULL if progress.
    14261519 */
    1427 int sh_add_child(shinstance *psh, shpid pid, void *hChild, KBOOL fProcess)
     1520int sh_add_child(shinstance *psh, shpid pid, void *hChild, shsubshellstatus *sts)
    14281521{
    14291522    /* get a free table entry. */
     
    14471540#endif
    14481541#ifndef SH_FORKED_MODE
    1449     psh->children[i].fProcess = fProcess;
    1450 #endif
    1451     (void)hChild; (void)fProcess;
     1542    psh->children[i].subshellstatus = sts;
     1543#endif
     1544    (void)hChild; (void)sts;
    14521545    return 0;
    14531546}
     
    14991592    shinstance * volatile volpsh = (shinstance *)user;
    15001593    shinstance *psh = (shinstance *)user;
     1594    shsubshellstatus *sts;
    15011595    struct jmploc exitjmp;
    15021596    int iExit;
     
    15271621        if (iExit == SH_EXIT_ZERO)
    15281622            iExit = 0;
     1623    }
     1624
     1625    /* Signal parent. */
     1626    sts = psh->subshellstatus;
     1627    if (sts)
     1628    {
     1629        BOOL rc;
     1630        HANDLE hThread;
     1631
     1632        sts->status = W_EXITCODE(iExit, 0);
     1633        sts->done   = K_TRUE;
     1634        rc = SetEvent((HANDLE)sts->towaiton); assert(rc); K_NOREF(rc);
     1635
     1636        hThread = (HANDLE)sts->hThread;
     1637        sts->hThread = 0;
     1638        rc = CloseHandle(hThread); assert(rc);
     1639
     1640        shsubshellstatus_release(psh, sts);
     1641        psh->subshellstatus = NULL;
    15291642    }
    15301643
     
    15461659{
    15471660# ifdef _MSC_VER
    1548     unsigned tid = 0;
    1549     uintptr_t hThread;
    15501661    shpid pid;
    15511662
    1552     pshchild->thread    = thread;
    1553     pshchild->threadarg = arg;
    1554     hThread = _beginthreadex(NULL /*security*/, 0 /*stack_size*/, sh_thread_wrapper, pshchild, 0 /*initflags*/, &tid);
    1555     if (hThread == -1)
    1556         return -errno;
    1557 
    1558     pid = SHPID_MAKE(SHPID_GET_PID(pshparent->pid), tid);
    1559     pshchild->pid = pid;
    1560     pshchild->tid = tid;
    1561 
    1562     if (sh_add_child(pshparent, pid, (void *)hThread, K_FALSE) != 0) {
    1563         return -ENOMEM;
    1564     }
     1663    shsubshellstatus *sts = shsubshellstatus_create(pshparent, 2);
     1664    pshchild->subshellstatus = sts;
     1665    if (sts)
     1666    {
     1667        unsigned tid = 0;
     1668        uintptr_t hThread;
     1669
     1670        pshchild->thread    = thread;
     1671        pshchild->threadarg = arg;
     1672
     1673        hThread = _beginthreadex(NULL /*security*/, 0 /*stack_size*/, sh_thread_wrapper, pshchild, 0 /*initflags*/, &tid);
     1674        sts->hThread = hThread;
     1675        if (hThread != -1)
     1676        {
     1677            pid = SHPID_MAKE(SHPID_GET_PID(pshparent->pid), tid);
     1678            pshchild->pid = pid;
     1679            pshchild->tid = tid;
     1680
     1681            if (sh_add_child(pshparent, pid, sts->towaiton, sts) == 0)
     1682            {
     1683                return pid;
     1684            }
     1685
     1686            shsubshellstatus_retain(sts);
     1687            pid = -ENOMEM;
     1688        }
     1689        else
     1690            pid = -errno;
     1691        shsubshellstatus_release(pshparent, sts);
     1692        shsubshellstatus_release(pshparent, sts);
     1693    }
     1694    else
     1695        pid = -ENOMEM;
    15651696    return pid;
    15661697
     
    16451776    if (i < psh->num_children)
    16461777    {
     1778        BOOL rc;
    16471779        if (hChild != INVALID_HANDLE_VALUE)
    16481780        {
    16491781            DWORD dwExitCode = 127;
    16501782#ifndef SH_FORKED_MODE
    1651             if (psh->children[i].fProcess ? GetExitCodeProcess(hChild, &dwExitCode) : GetExitCodeThread(hChild, &dwExitCode))
    1652 #else
     1783            if (psh->children[i].subshellstatus)
     1784            {
     1785                rc = psh->children[i].subshellstatus->done;
     1786                assert(rc);
     1787                if (rc)
     1788                {
     1789                    *statusp = psh->children[i].subshellstatus->status;
     1790                    pidret = psh->children[i].pid;
     1791                }
     1792            }
     1793            else
     1794#endif
    16531795            if (GetExitCodeProcess(hChild, &dwExitCode))
    1654 #endif
    16551796            {
    16561797                pidret = psh->children[i].pid;
     
    16631804        }
    16641805
    1665         /* remove and close */
    1666         hChild = psh->children[i].hChild;
     1806        /* close and remove */
     1807        if (psh->children[i].subshellstatus)
     1808        {
     1809            shsubshellstatus_release(psh, psh->children[i].subshellstatus);
     1810            psh->children[i].subshellstatus = NULL;
     1811        }
     1812        else
     1813        {
     1814            rc = CloseHandle(psh->children[i].hChild);
     1815            assert(rc);
     1816        }
     1817
    16671818        psh->num_children--;
    16681819        if (i < psh->num_children)
    16691820            psh->children[i] = psh->children[psh->num_children];
    1670         i = CloseHandle(hChild); assert(i);
     1821        psh->children[psh->num_children].hChild = NULL;
     1822        psh->children[psh->num_children].subshellstatus = NULL;
    16711823    }
    16721824
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette