Как отправить стандартный вывод на общий mmap? - PullRequest
1 голос
/ 05 марта 2020

Это домашнее задание. Задача состоит в том, чтобы реплицировать команду оболочки: ls | wc -l в C, используя общую память с mmap() при соблюдении стандартов POSIX.

Вот мой оригинальный подход к проблеме:

  1. Создание области общей памяти sh_mem
  2. Форк процесса
  3. Внутри дочернего процесса:
    • Привязка stdout для записи в sh_mem каким-либо образом
    • Позвоните execlp("ls", "ls", NULL)
  4. Внутри родительского процесса:
    • wait(NULL) для завершения ребенком
    • Привязка stdin для чтения с sh_mem как-то
    • Звоните execlp("wc", "wc", "-l", NULL)

Проблема:

Однако я не мог думать о том, как связать stdin / stdout с sh_mem. Я сделал это с помощью конвейеров и подумал, что смогу реализовать нечто подобное здесь, но я не смог найти никаких путей.

Можете ли вы дать мне советы, как решить эту проблему?

Код: (не полный)

Вот мой код, который я написал до сих пор, но сейчас он довольно бесполезен. Он просто пишет и читает от ребенка и родителя.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h> 
#include <errno.h> 
#include <sys/wait.h>
#include <sys/mman.h>
#include <string.h>

int main() {
    const char* p_msg = "Hello";
    const char* c_msg = "World";

    void* shmem = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

    memcpy(shmem, p_msg, sizeof(p_msg));

    int pid = fork();

    if(pid == 0){
        printf("Child reads: %s\n", shmem);
        memcpy(shmem, c_msg, sizeof(c_msg));
    }
    else {
        printf("Parent reads: %s\n", shmem);
        sleep(1);
        printf("after one sec: %s\n", shmem);
    }
}

Возможное решение 1:

Я подумал о другом подходе, где я использую файл для записи и получения карта памяти в файл. Но тогда я не вижу утилиты разделяемой памяти, если файл используется для фактического чтения и записи.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h> 
#include <errno.h> 
#include <sys/wait.h>
#include <sys/mman.h>
#include <string.h>

int main() {
    int returnstatus;

    // Create a file
    int fd = open("shmem.txt", O_RDWR | O_CREAT, O_RDWR);

    // Create a memory map of the file
    void* sh_mem = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);


    // Create a child process   int pid = fork();

    if(pid == 0){
        // Inside Child process
        // Link stdout to file

        dup2(fd, 1);    

        // Close unused fd
        close(fd)       

        // Execute ls
        execlp("ls", "ls", NULL);

    else {
        // Inside Parent Process

        // Link stdin to file/sh_mem

        // Execute wc
    }

}


Возможное решение 2:

Предложено @kaylum. Используйте shm_open(), чтобы получить fd в общую память.

Я пробовал, но это не работает, как я ожидал. Он не связывает ни stdout, ни stdin


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h> 
#include <errno.h> 
#include <sys/wait.h>
#include <sys/mman.h>
#include <string.h>

int main() {
    int returnstatus;

    // Get the fd of the map
    int fd = open("sh.file", O_RDWR, O_RDWR);

    // Create a memory map of the file
    void* sh_mem = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

    // Create a child process
    int pid = fork();

    if(pid == 0){
        // Inside Child process
        // Link stdout to file
        dup2(fd, 1);    

        // Close unused fd
        close(fd);      

        // Execute ls
        execlp("ls", "ls", NULL);
    }   
    else { // Inside Parent Process
        // Link stdin to file
        dup2(fd, 0);

        // CLose unused fd
        close(fd);

        // Execute wc
        execlp("wc", "wc", "-l", NULL);
    }

}


...