Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/src/win32/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 10 kB image not shown  

Quelle  process.c   Sprache: C

 

// SPDX-License-Identifier: LGPL-2.1-or-later
/*****************************************************************************
 * process.c: win32 implementation of process management
 *****************************************************************************
 * Copyright © 2025 Videolabs, VideoLAN and VLC authors
 *
 * Authors: Gabriel Lafond Thenaille <gabriel@videolabs.io>
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <windows.h>
#include <io.h>
#include <assert.h>
#include <stdatomic.h>

#include <vlc_common.h>
#include <vlc_process.h>
#include <vlc_interrupt.h>
#include <vlc_spawn.h>
#include <vlc_fs.h>

static_assert(HAVE_VLC_PROCESS_SPAWN == 1, "mismatching HAVE_VLC_PROCESS_SPAWN declaration");

static void CALLBACK
vlc_process_WindowsPoll_i11e_wake_self(ULONG_PTR data)
{
    (void) data;
}

static void
vlc_process_WindowsPoll_i11e_wake(void *opaque)
{
    assert(opaque != NULL);

    HANDLE th = opaque;
    QueueUserAPC(vlc_process_WindowsPoll_i11e_wake_self, th, 0);
}

/**
 * Map the result of a failed overlapped operation to an errno-like value.
 */

static int
vlc_process_WindowsMapIoResult(DWORD error, DWORD *bytes, bool is_read,
                               int dflt)
{
    if (is_read) {
        if (error == ERROR_BROKEN_PIPE || error == ERROR_HANDLE_EOF) {
            *bytes = 0;
            return VLC_SUCCESS;
        }
    } else if (error == ERROR_BROKEN_PIPE || error == ERROR_NO_DATA ||
               error == ERROR_PIPE_NOT_CONNECTED) {
        return EPIPE;
    }
    return dflt;
}

/**
 * Cancel a pending overlapped operation and wait for its completion.
 */

static int vlc_process_WindowsCancelPoll(HANDLE hFd, LPOVERLAPPED lpoverlapped,
                                         DWORD *bytes, DWORD size,
                                         bool is_read, int cancel_err)
{
    CancelIoEx(hFd, lpoverlapped);
    if (GetOverlappedResult(hFd, lpoverlapped, bytes, TRUE)) {
        return VLC_SUCCESS;
    }

    DWORD error = GetLastError();
    if (error == ERROR_OPERATION_ABORTED) {
        if (*bytes > 0 && *bytes <= size) {
            return VLC_SUCCESS;
        }
        *bytes = 0;
        return cancel_err;
    }
    return vlc_process_WindowsMapIoResult(error, bytes, is_read, EINVAL);
}

static int
vlc_process_WindowsPoll(HANDLE hFd, LPOVERLAPPED lpoverlapped, DWORD *bytes,
                        DWORD size, bool is_read, vlc_tick_t timeout_ms)
{
    HANDLE th;
    if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
                         GetCurrentProcess(), &th, 0, FALSE,
                         DUPLICATE_SAME_ACCESS)) {
        return vlc_process_WindowsCancelPoll(hFd, lpoverlapped, bytes, size,
                                             is_read, ENOMEM);
    }
    vlc_interrupt_register(vlc_process_WindowsPoll_i11e_wake, th);
    DWORD waitResult = WaitForSingleObjectEx(lpoverlapped->hEvent,
                                             timeout_ms, TRUE);
    int interrupted = vlc_interrupt_unregister();
    CloseHandle(th);

    if (interrupted != 0) {
        return vlc_process_WindowsCancelPoll(hFd, lpoverlapped, bytes, size,
                                             is_read, EINTR);
    }

    switch (waitResult) {
        case WAIT_OBJECT_0:
            if (GetOverlappedResult(hFd, lpoverlapped, bytes, FALSE)) {
                return VLC_SUCCESS;
            }
            return vlc_process_WindowsMapIoResult(GetLastError(), bytes,
                                                  is_read, EINVAL);
        case WAIT_TIMEOUT:
            /* Timeout occurred */
            return vlc_process_WindowsCancelPoll(hFd, lpoverlapped, bytes,
                                                 size, is_read, ETIMEDOUT);
        case WAIT_IO_COMPLETION:
            /* Interrupt occurred */
            return vlc_process_WindowsCancelPoll(hFd, lpoverlapped, bytes,
                                                 size, is_read, EINTR);
        default:
            return vlc_process_WindowsCancelPoll(hFd, lpoverlapped, bytes,
                                                 size, is_read, EINVAL);
    }
}

struct vlc_process {
    /* Pid of the linked process */
    pid_t pid;

    HANDLE hProcess;

    int fd_in;
    int fd_out;

    HANDLE hEventRead;
    HANDLE hEventWrite;

    atomic_bool killed;
};

struct vlc_process*
vlc_process_Spawn(const char *path, int argc, const char *const *argv)
{
    assert(path != NULL);
    if (argc > 0) {
        assert(argv != NULL);
        assert(argv[0] != NULL);
    }

    int ret = VLC_EGENERIC;
    int fds[2] = { -1, -1 };
    int extfd_in = -1;
    int extfd_out = -1;
    const char **args = NULL;

    struct vlc_process *process = malloc(sizeof(*process));
    if (process == NULL) {
        return NULL;
    }

    process->fd_in = -1;
    process->fd_out = -1;
    process->hProcess = NULL;
    process->hEventRead = NULL;
    process->hEventWrite = NULL;
    atomic_init(&process->killed, false);

    process->hEventRead = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (process->hEventRead == NULL) {
        ret = VLC_ENOMEM;
        goto end;
    }

    process->hEventWrite = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (process->hEventWrite == NULL) {
        ret = VLC_ENOMEM;
        goto end;
    }

    ret = vlc_pipe(fds);
    if (ret != 0) {
        goto end;
    }
    extfd_out = fds[1];
    process->fd_in = fds[0];

    ret = vlc_pipe(fds);
    if (ret != 0) {
        goto end;
    }
    extfd_in = fds[0];
    process->fd_out = fds[1];

    int stderr_fd = -1;
    intptr_t h_err = _get_osfhandle(STDERR_FILENO);
    if (h_err != -1 && h_err != -2) {
        stderr_fd = STDERR_FILENO;
    }

    int process_fds[4] = {extfd_in, extfd_out, stderr_fd, -1};

    /* `argc + 2`, 1 for the process->path and the last to be NULL */
    args = malloc((argc + 2) * sizeof(*args));
    if (args == NULL) {
        ret = VLC_ENOMEM;
        goto end;
    }
    args[0] = path;
    for (int i = 0; i < argc; i++) {
        args[i + 1] = argv[i];
    }
    args[argc + 1] = NULL;

    ret = vlc_spawnp(&process->pid, path, process_fds, args);
    if (ret != 0) {
        goto end;
    }

    process->hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, process->pid);

end:

    free(args);

    if (extfd_in != -1) {
        vlc_close(extfd_in);
    }
    if (extfd_out != -1) {
        vlc_close(extfd_out);
    }

    if (ret != 0) {
        if (process->fd_in != -1) {
            vlc_close(process->fd_in);
        }
        if (process->fd_out != -1) {
            vlc_close(process->fd_out);
        }
        if (process->hEventRead != NULL) {
            CloseHandle(process->hEventRead);
        }
        if (process->hEventWrite != NULL) {
            CloseHandle(process->hEventWrite);
        }
        free(process);
        return NULL;
    }
    return process;
}

void
vlc_process_Kill(struct vlc_process *process)
{
    assert(process != NULL);

    if (process->hProcess != NULL) {
        TerminateProcess(process->hProcess, 15);
    }

    atomic_store(&process->killed, true);

    intptr_t h_in = _get_osfhandle(process->fd_in);
    if (h_in != -1 && h_in != -2) {
        CancelIoEx((HANDLE)h_in, NULL);
    }
    intptr_t h_out = _get_osfhandle(process->fd_out);
    if (h_out != -1 && h_out != -2) {
        CancelIoEx((HANDLE)h_out, NULL);
    }
}

int
vlc_process_Terminate(struct vlc_process *process, bool kill_process)
{
    assert(process != NULL);

    if (kill_process) {
        vlc_process_Kill(process);
    }

    vlc_close(process->fd_in);
    vlc_close(process->fd_out);
    CloseHandle(process->hEventRead);
    CloseHandle(process->hEventWrite);

    int status = vlc_waitpid(process->pid);
    if (process->hProcess != NULL) {
        CloseHandle(process->hProcess);
    }
    process->pid = 0;
    free(process);
    return status;
}

ssize_t
vlc_process_fd_Read(struct vlc_process *process, uint8_t *buf, size_t size,
                    vlc_tick_t timeout_ms)
{
    assert(process != NULL);
    assert(buf != NULL);

    /* The channel is shut down, report end-of-stream like POSIX does. */
    if (atomic_load(&process->killed)) {
        return 0;
    }

    intptr_t h = _get_osfhandle(process->fd_in);
    if (h == -1) {
        errno = EINVAL;
        return -1;
    }
    HANDLE hFd = (HANDLE)h;

    DWORD bytes = 0;
    OVERLAPPED overlapped = {0};
    overlapped.hEvent = process->hEventRead;

    /* The event is reused across calls, drop any leftover completion. */
    ResetEvent(process->hEventRead);

    int err;
    if (ReadFile(hFd, buf, size, NULL, &overlapped)) {
        if (GetOverlappedResult(hFd, &overlapped, &bytes, FALSE)) {
            err = VLC_SUCCESS;
        } else {
            err = vlc_process_WindowsMapIoResult(GetLastError(), &bytes, true,
                                                 EINVAL);
        }
    } else {
        DWORD error = GetLastError();
        if (error == ERROR_IO_PENDING) {
            if (atomic_load(&process->killed)) {
                CancelIoEx(hFd, &overlapped);
            }
            err = vlc_process_WindowsPoll(hFd, &overlapped, &bytes,
                                          (DWORD)size, true, timeout_ms);
        } else {
            err = vlc_process_WindowsMapIoResult(error, &bytes, true, EINVAL);
        }
    }

    if (err == VLC_SUCCESS) {
        return bytes;
    }
    if (atomic_load(&process->killed)) {
        return 0;
    }
    errno = err;
    return -1;
}

ssize_t
vlc_process_fd_Write(struct vlc_process *process, const uint8_t *buf, size_t size,
                     vlc_tick_t timeout_ms)
{
    assert(process != NULL);
    assert(buf != NULL);

    if (atomic_load(&process->killed)) {
        errno = EPIPE;
        return -1;
    }

    intptr_t h = _get_osfhandle(process->fd_out);
    if (h == -1) {
        errno = EINVAL;
        return -1;
    }
    HANDLE hFd = (HANDLE)h;

    DWORD bytes = 0;
    OVERLAPPED overlapped = {0};
    overlapped.hEvent = process->hEventWrite;

    /* The event is reused across calls, drop any leftover completion. */
    ResetEvent(process->hEventWrite);

    int err;
    if (WriteFile(hFd, buf, size, NULL, &overlapped)) {
        if (GetOverlappedResult(hFd, &overlapped, &bytes, FALSE)) {
            err = VLC_SUCCESS;
        } else {
            err = vlc_process_WindowsMapIoResult(GetLastError(), &bytes, false,
                                                 EINVAL);
        }
    } else {
        DWORD error = GetLastError();
        if (error == ERROR_IO_PENDING) {
            if (atomic_load(&process->killed)) {
                CancelIoEx(hFd, &overlapped);
            }
            err = vlc_process_WindowsPoll(hFd, &overlapped, &bytes,
                                          (DWORD)size, false, timeout_ms);
        } else {
            err = vlc_process_WindowsMapIoResult(error, &bytes, false, EINVAL);
        }
    }

    if (err == VLC_SUCCESS) {
        return bytes;
    }
    errno = atomic_load(&process->killed) ? EPIPE : err;
    return -1;
}

Messung
CHZG
849510093

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.