Changeset 2293 for trunk/src


Ignore:
Timestamp:
Feb 28, 2009, 8:25:12 AM (16 years ago)
Author:
bird
Message:

kash: forking on windows (almost there).

Location:
trunk/src/kash
Files:
9 edited

Legend:

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

    r2290 r2293  
    451451}
    452452
     453#if K_OS == K_OS_WINDOWS && defined(SHFILE_IN_USE) //&& defined(SH_FORKED_MODE)
     454/**
     455 * Helper for shfork.
     456 *
     457 * @param   pfdtab  The file descriptor table.
     458 * @param   set     Whether to make all handles inheritable (1) or
     459 *                  to restore them to the rigth state (0).
     460 * @param   hndls   Where to store the three standard handles.
     461 */
     462void shfile_fork_win(shfdtab *pfdtab, int set, intptr_t *hndls)
     463{
     464    shmtxtmp tmp;
     465    unsigned i;
     466
     467    shmtx_enter(&pfdtab->mtx, &tmp);
     468
     469    i = pfdtab->size;
     470    while (i-- > 0)
     471    {
     472        if (pfdtab->tab[i].fd == i)
     473        {
     474            HANDLE hFile = (HANDLE)pfdtab->tab[i].native;
     475            DWORD  fFlag = set || !pfdtab->tab[i].cloexec ? HANDLE_FLAG_INHERIT : 0;
     476            if (!SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, fFlag))
     477            {
     478                DWORD err = GetLastError();
     479                assert(0);
     480            }
     481        }
     482    }
     483
     484    if (hndls)
     485    {
     486        for (i = 0; i < 3; i++)
     487        {
     488            if (    pfdtab->size > i
     489                &&  pfdtab->tab[i].fd == 0)
     490                hndls[i] = pfdtab->tab[i].native;
     491            else
     492                hndls[i] = (intptr_t)INVALID_HANDLE_VALUE;
     493        }
     494    }
     495
     496    shmtx_leave(&pfdtab->mtx, &tmp);
     497}
     498#endif
     499
     500
    453501/**
    454502 * open().
  • trunk/src/kash/shfile.h

    r2290 r2293  
    119119
    120120int shfile_init(shfdtab *, shfdtab *);
     121void shfile_fork_win(shfdtab *pfdtab, int set, intptr_t *hndls);
    121122
    122123int shfile_open(shfdtab *, const char *, unsigned, mode_t);
  • trunk/src/kash/shfork-win.c

    r2292 r2293  
    77#include <locale.h>
    88#include "shinstance.h"
     9#include <Windows.h>
     10
     11/*******************************************************************************
     12*   Defined Constants And Macros                                               *
     13*******************************************************************************/
     14/** The stack size. This is also defined in shforkA-win.asm. */
     15#define SHFORK_STACK_SIZE (1*1024*1024)
    916
    1017
     
    2633/* called by shforkA-win.asm: */
    2734void *shfork_maybe_forked(int argc, char **argv, char **envp);
    28 extern int shfork_body(uintptr_t stack_ptr);
     35extern int shfork_body(shinstance *psh, void *stack_ptr);
    2936
    3037
     
    5663        ||  strcmp(argv[6], "--stack-limit"))
    5764    {
     65        char *stack;
    5866        shheap_init();
    59         return (char *)sh_malloc(NULL, 1*1024*1024) + 1*1024*1024;
     67        stack = (char *)sh_malloc(NULL, SHFORK_STACK_SIZE) + SHFORK_STACK_SIZE;
     68        g_stack_base = stack + SHFORK_STACK_SIZE;
     69        g_stack_limit = stack;
     70        return stack;
    6071    }
    6172
     
    6475     * fork() call.
    6576     */
    66         setlocale(LC_ALL, "");
     77    setlocale(LC_ALL, "");
    6778
    6879    /*
     
    121132        ptr <<= 4;
    122133        ptr |= digit;
     134        str++;
    123135    }
    124136    return (void *)ptr;
     
    132144 *
    133145 * @returns child pid on success, -1 and errno on failure.
     146 * @param   psh             The shell that's forking.
    134147 * @param   stack_ptr       The stack address at which the guest is suppost to resume.
    135148 */
    136 int shfork_body(uintptr_t stack_ptr)
     149int shfork_body(shinstance *psh, void *stack_ptr)
    137150{
    138     errno = ENOSYS;
    139     return -1;
     151    PROCESS_INFORMATION ProcInfo;
     152    STARTUPINFO StrtInfo;
     153    intptr_t hndls[3];
     154    char szExeName[1024];
     155    char szCmdLine[1024+256];
     156    DWORD cch;
     157    int rc = 0;
     158
     159    /*
     160     * Mark all handles inheritable and get the three standard handles.
     161     */
     162    shfile_fork_win(&psh->fdtab, 1 /* set */, &hndls[0]);
     163
     164    /*
     165     * Create the process.
     166     */
     167    cch = GetModuleFileName(GetModuleHandle(NULL), szExeName, sizeof(szExeName));
     168    if (cch > 0)
     169    {
     170#if 0 /* quoting the program name doesn't seems to be working :/ */
     171        szCmdLine[0] = '"';
     172        memcpy(&szCmdLine[1], szExeName, cch);
     173        szCmdLine[++cch] = '"';
     174#else
     175        memcpy(&szCmdLine[0], szExeName, cch);
     176#endif
     177        cch += sprintf(&szCmdLine[cch], " --!forked!-- --stack-address %p --stack-base %p --stack-limit %p",
     178                       stack_ptr, g_stack_base, g_stack_limit);
     179        szCmdLine[cch+1] = '\0';
     180
     181        memset(&StrtInfo, '\0', sizeof(StrtInfo)); /* just in case. */
     182        StrtInfo.cb = sizeof(StrtInfo);
     183        StrtInfo.lpReserved = NULL;
     184        StrtInfo.lpDesktop = NULL;
     185        StrtInfo.lpTitle = NULL;
     186        StrtInfo.dwX = 0;
     187        StrtInfo.dwY = 0;
     188        StrtInfo.dwXSize = 0;
     189        StrtInfo.dwYSize = 0;
     190        StrtInfo.dwXCountChars = 0;
     191        StrtInfo.dwYCountChars = 0;
     192        StrtInfo.dwFillAttribute = 0;
     193        StrtInfo.dwFlags = 0;
     194        StrtInfo.wShowWindow = 0;
     195        StrtInfo.cbReserved2 = 0;
     196        StrtInfo.lpReserved2 = NULL;
     197        StrtInfo.hStdInput  = (HANDLE)hndls[0];
     198        StrtInfo.hStdOutput = (HANDLE)hndls[1];
     199        StrtInfo.hStdError  = (HANDLE)hndls[2];
     200        if (CreateProcess(szExeName,
     201                          szCmdLine,
     202                          NULL,         /* pProcessAttributes */
     203                          NULL,         /* pThreadAttributes */
     204                          TRUE,         /* bInheritHandles */
     205                          CREATE_SUSPENDED,
     206                          NULL,         /* pEnvironment */
     207                          NULL,         /* pCurrentDirectory */
     208                          &StrtInfo,
     209                          &ProcInfo))
     210        {
     211            /*
     212             * Copy the memory to the child.
     213             */
     214            rc = shheap_fork_copy_to_child(ProcInfo.hProcess);
     215            if (!rc)
     216            {
     217                if (ResumeThread(ProcInfo.hThread) != (DWORD)-1)
     218                {
     219                    rc = sh_add_child(psh, ProcInfo.dwProcessId, ProcInfo.hProcess);
     220                    if (!rc)
     221                        rc = (int)ProcInfo.dwProcessId;
     222                }
     223                else
     224                {
     225                    DWORD dwErr = GetLastError();
     226                    fprintf(stderr, "shfork: ResumeThread() -> %d\n", dwErr);
     227                    errno = EINVAL;
     228                    rc = -1;
     229                }
     230            }
     231            if (rc == -1)
     232            {
     233                TerminateProcess(ProcInfo.hProcess, 127);
     234                /* needed?: ResumeThread(ProcInfo.hThread); */
     235                CloseHandle(ProcInfo.hProcess);
     236            }
     237            CloseHandle(ProcInfo.hThread);
     238        }
     239        else
     240        {
     241            DWORD dwErr = GetLastError();
     242            fprintf(stderr, "shfork: CreateProcess(%s) -> %d\n", szExeName, dwErr);
     243            errno = EINVAL;
     244            rc = -1;
     245        }
     246    }
     247    else
     248    {
     249        DWORD dwErr = GetLastError();
     250        fprintf(stderr, "shfork: GetModuleFileName() -> %d\n", dwErr);
     251        errno = EINVAL;
     252        rc = -1;
     253    }
     254
     255    /*
     256     * Restore the handle inherit property.
     257     */
     258    shfile_fork_win(&psh->fdtab, 0 /* restore */, NULL);
     259
     260    return rc;
    140261}
  • trunk/src/kash/shforkA-win.asm

    r2292 r2293  
    3232 %define NAME(name) _ %+ name
    3333%endif
     34
     35;; The stack size. This is also defined in shfork-win.c.
     36%define SHFORK_STACK_SIZE (1*1024*1024)
    3437
    3538
     
    108111        mov     [gs:08h], rax
    109112.below:
    110         lea     r9, [rax - 1*1024*1024]
     113        lea     r9, [rax - SHFORK_STACK_SIZE]
    111114        cmp     r9, r11
    112115        ja      .above
     
    132135        mov     [fs:04h], rax
    133136.below:
    134         lea     edx, [eax - 1*1024*1024]
     137        lea     edx, [eax - SHFORK_STACK_SIZE]
    135138        cmp     edx, ecx
    136139        ja      .above
     
    175178;;
    176179; sh_fork() worker
     180;
     181; @returns      See fork().
     182; @param        psh
    177183;
    178184NAME(shfork_do_it):
     
    230236        ;
    231237%ifdef KBUILD_ARCH_AMD64
    232         mov     rcx, rsp
    233 %else
    234         mov     ecx, esp
     238        ;mov     rcx, rcx               ; psh
     239        mov     rdx, rsp                ; stack_ptr
     240        sub     rsp, 20h
     241        call    NAME(shfork_body)
     242        lea     rsp, [rsp + 20h]
     243%else
     244        mov     edx, esp
     245        mov     ecx, [ebp + 8h]         ; psh
    235246        sub     esp, 20h
    236         mov     [esp], ecx
    237 %endif
     247        mov     [esp    ], edx
     248        mov     [esp + 4], ecx          ; stack_ptr
    238249        call    NAME(shfork_body)
    239 %ifdef KBUILD_ARCH_AMD64
    240250        lea     esp, [esp + 20h]
    241251%endif
  • trunk/src/kash/shheap.c

    r2292 r2293  
    137137#ifdef SHHEAP_IN_USE
    138138
     139# if K_OS == K_OS_WINDOWS
     140/**
     141 * Copies the heap into the child process.
     142 *
     143 * @returns 0 on success, -1 and errno on failure.
     144 * @param   hChild      Handle to the child process.
     145 */
     146int shheap_fork_copy_to_child(void *hChild)
     147{
     148    shmemchunk *chunk;
     149    shmtxtmp tmp;
     150    int err = 0;
     151
     152    shmtx_enter(&g_sh_heap_mtx, &tmp);
     153
     154    for (chunk = g_sh_heap; chunk; chunk = chunk->next)
     155    {
     156        void *chld_chnk;
     157
     158        chld_chnk = (shmemchunk *)VirtualAllocEx(hChild, chunk, chunk->size,
     159                                                 MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
     160        if (chld_chnk != chunk)
     161        {
     162            err = GetLastError();
     163            fprintf(stderr, "shfork: VirtualAllocEx(,%p,%p,) -> %d\n", chunk, chunk->size, err);
     164            break;
     165        }
     166
     167        if (!WriteProcessMemory(hChild, chunk, chunk, chunk->size, NULL /* pNumberOfBytesWritten */))
     168        {
     169            err = GetLastError();
     170            fprintf(stderr, "shfork: WriteProcessMemory(,%p,,%p,) -> %d\n", chunk, chunk->size, err);
     171            break;
     172        }
     173    }
     174
     175    shmtx_leave(&g_sh_heap_mtx, &tmp);
     176
     177    if (!err)
     178        return 0;
     179    errno = EINVAL;
     180    return -1;
     181}
     182# endif
     183
     184
    139185/**
    140186 * Checks a heap chunk.
  • trunk/src/kash/shheap.h

    r2292 r2293  
    3333/* heap */
    3434int shheap_init(void);
     35int shheap_fork_copy_to_child(void *);
     36
    3537void *sh_malloc(shinstance *, size_t);
    3638void *sh_calloc(shinstance *, size_t, size_t);
  • trunk/src/kash/shinstance.c

    r2292 r2293  
    3838# include <pwd.h>
    3939#endif
     40#if K_OS == K_OS_WINDOWS
     41# include <Windows.h>
     42#endif
    4043#include "shinstance.h"
    4144
    4245#if K_OS == K_OS_WINDOWS
    43 extern pid_t shfork_do_it(void); /* shforkA-win.asm */
     46extern pid_t shfork_do_it(shinstance *psh); /* shforkA-win.asm */
    4447#endif
    4548
     
    308311}
    309312
     313/** getenv() */
    310314char *sh_getenv(shinstance *psh, const char *var)
    311315{
     
    868872}
    869873
     874/**
     875 * Adds a child to the shell
     876 *
     877 * @returns 0 on success, on failure -1 and errno set to ENOMEM.
     878 *
     879 * @param   psh     The shell instance.
     880 * @param   pid     The child pid.
     881 * @param   hChild  Windows child handle.
     882 */
     883int sh_add_child(shinstance *psh, pid_t pid, void *hChild)
     884{
     885    /* get a free table entry. */
     886    int i = psh->num_children++;
     887    if (!(i % 32))
     888    {
     889        void *ptr = sh_realloc(psh, psh->children, sizeof(*psh->children) * (i + 32));
     890        if (!ptr)
     891        {
     892            psh->num_children--;
     893            errno = ENOMEM;
     894            return -1;
     895        }
     896        psh->children = ptr;
     897    }
     898
     899    /* add it */
     900    psh->children[i].pid = pid;
     901#if K_OS == K_OS_WINDOWS
     902    psh->children[i].hChild = hChild;
     903#endif
     904    (void)hChild;
     905    return 0;
     906}
     907
    870908pid_t sh_fork(shinstance *psh)
    871909{
     
    877915
    878916#elif K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
    879     pid = shfork_do_it();
     917    pid = shfork_do_it(psh);
    880918
    881919#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
     
    896934}
    897935
     936/** waitpid() */
    898937pid_t sh_waitpid(shinstance *psh, pid_t pid, int *statusp, int flags)
    899938{
    900939    pid_t pidret;
    901 
     940#ifdef SH_PURE_STUB_MODE
    902941    *statusp = 0;
    903 #ifdef SH_PURE_STUB_MODE
    904942    pidret = -1;
    905943
    906 #elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
     944#elif K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
     945    DWORD   dwRet;
     946    HANDLE  hChild = INVALID_HANDLE_VALUE;
     947    int     i;
     948
     949    *statusp = 0;
     950    pidret = -1;
     951    if (pid != -1)
     952    {
     953        /*
     954         * A specific child, try look it up in the child process table
     955         * and wait for it.
     956         */
     957        for (i = 0; i < psh->num_children; i++)
     958            if (psh->children[i].pid == pid)
     959                break;
     960        if (i < psh->num_children)
     961        {
     962            dwRet = WaitForSingleObject(psh->children[i].hChild,
     963                                        flags & WNOHANG ? 0 : INFINITE);
     964            if (dwRet == WAIT_OBJECT_0)
     965                hChild = psh->children[i].hChild;
     966            else if (dwRet == WAIT_TIMEOUT)
     967            {
     968                i = -1; /* don't try close anything */
     969                pidret = 0;
     970            }
     971            else
     972                errno = ECHILD;
     973        }
     974        else
     975            errno = ECHILD;
     976    }
     977    else if (psh->num_children <= MAXIMUM_WAIT_OBJECTS)
     978    {
     979        HANDLE ahChildren[64];
     980        for (i = 0; i < psh->num_children; i++)
     981            ahChildren[i] = psh->children[i].hChild;
     982        dwRet = WaitForMultipleObjects(psh->num_children, &ahChildren[0],
     983                                       FALSE,
     984                                       flags & WNOHANG ? 0 : INFINITE);
     985        i = dwRet - WAIT_OBJECT_0;
     986        if ((unsigned)i < (unsigned)psh->num_children)
     987        {
     988            hChild = psh->children[i].hChild;
     989        }
     990        else if (dwRet == WAIT_TIMEOUT)
     991        {
     992            i = -1; /* don't try close anything */
     993            pidret = 0;
     994        }
     995        else
     996        {
     997            i = -1; /* don't try close anything */
     998            errno = EINVAL;
     999        }
     1000    }
     1001    else
     1002    {
     1003        fprintf(stderr, "panic! too many children!\n");
     1004        i = -1;
     1005        *(char *)1 = '\0'; /** @todo implement this! */
     1006    }
     1007
     1008    /*
     1009     * Close the handle, and if we succeeded collect the exit code first.
     1010     */
     1011    if (    i >= 0
     1012        &&  i < psh->num_children)
     1013    {
     1014        if (hChild != INVALID_HANDLE_VALUE)
     1015        {
     1016            DWORD dwExitCode = 127;
     1017            if (GetExitCodeProcess(hChild, &dwExitCode))
     1018            {
     1019                pidret = psh->children[i].pid;
     1020                if (dwExitCode && !W_EXITCODE(dwExitCode, 0))
     1021                    dwExitCode |= 16;
     1022                *statusp = W_EXITCODE(dwExitCode, 0);
     1023            }
     1024            else
     1025                errno = EINVAL;
     1026        }
     1027
     1028        /* remove and close */
     1029        hChild = psh->children[i].hChild;
     1030        psh->num_children--;
     1031        if (i < psh->num_children)
     1032            psh->children[i] = psh->children[psh->num_children];
     1033        i = CloseHandle(hChild); assert(i);
     1034    }
     1035
     1036#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
     1037    *statusp = 0;
    9071038# ifdef _MSC_VER
    9081039    pidret = -1;
  • trunk/src/kash/shinstance.h

    r2291 r2293  
    5959#endif
    6060
     61/**
     62 * A child process.
     63 */
     64typedef struct shchild
     65{
     66    pid_t       pid;                    /**< The pid. */
     67#if K_OS == K_OS_WINDOWS
     68    void       *hChild;                 /**< The process handle. */
     69#endif
     70} shchild;
    6171
    6272/* memalloc.c */
     
    135145    shsigset_t          sigmask;        /**< Our signal mask. */
    136146    char              **shenviron;      /**< The environment vector. */
     147    int                 num_children;   /**< Number of children in the array. */
     148    shchild            *children;       /**< The child array. */
    137149
    138150    /* alias.c */
     
    396408
    397409/* wait / process */
     410int sh_add_child(shinstance *psh, pid_t pid, void *hChild);
    398411#ifdef _MSC_VER
    399412#   include <process.h>
  • trunk/src/kash/show.c

    r2289 r2293  
    274274trputc(shinstance *psh, int c)
    275275{
    276         if (debug(psh) != 1)
     276        if (psh && debug(psh) != 1)
    277277                return;
    278278        putc(c, tracefile);
     
    287287        va_list va;
    288288
    289         if ((psh || !tracefile) && debug(psh) != 1)
    290                 return;
    291         fprintf(tracefile, "[%d] ", sh_getpid(psh));
     289        if (!tracefile || (psh && debug(psh) != 1))
     290                return;
     291        fprintf(tracefile, "[%d] ", sh_getpid(psh));
    292292        va_start(va, fmt);
    293293        (void) vfprintf(tracefile, fmt, va);
     
    304304        int savederrno = errno;
    305305
    306         if ((psh || !tracefile) && debug(psh) != 1)
    307                 return;
    308         fprintf(tracefile, "[%d] ", sh_getpid(psh));
     306        if (!tracefile || (psh && debug(psh) != 1))
     307                return;
     308        fprintf(tracefile, "[%d] ", sh_getpid(psh));
    309309        (void) vfprintf(tracefile, fmt, va);
    310310
     
    320320        int savederrno = errno;
    321321
    322         if ((psh || !tracefile) && debug(psh) != 1)
     322        if (!tracefile || (psh && debug(psh) != 1))
    323323                return;
    324324        fputs(s, tracefile);
     
    335335        char c;
    336336
    337         if ((psh || !tracefile) && debug(psh) != 1)
     337        if (!tracefile || (psh && debug(psh) != 1))
    338338                return;
    339339        putc('"', tracefile);
     
    378378        int savederrno = errno;
    379379
    380         if ((psh || !tracefile) && debug(psh) != 1)
     380        if (!tracefile || (psh && debug(psh) != 1))
    381381                return;
    382382        while (*ap) {
     
    400400        int fd;
    401401
    402         if (debug(psh) != 1) {
     402        if (psh && debug(psh) != 1) {
    403403                if (tracefile)
    404404                        fflush(tracefile);
Note: See TracChangeset for help on using the changeset viewer.