MacOS X,C:shm_open失败并且errno 13后续运行中的权限被拒绝

时间:2014-01-26 19:48:30

标签: macos semaphore shared-memory mmap

我正在尝试使用shm_open和mmap以及信号量在MacOS X上的两个进程之间共享一块内存。

我遇到的一个问题是,当我运行程序第二次时,当我尝试调用 shm_open()时出现权限错误。

    #include "SharedMemory.h"

    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <unistd.h>
    #include <semaphore.h>
    #include <pthread.h>
    #include <cassert>

    void * run_task(void * context);


    const char * mem_name = "/tmp/my_mem2";
    const char * sem_name = "/tmp/my_sem2";

    int gFileDescr = -1;

    void * gSharedMemoryAddr = NULL;
    size_t gSharedMemorySize = 0;

    sem_t * gSharedMemorySemaphore = NULL;



    typedef struct {
        completion_proc_t callback;
        void * context;
    } CallbackAndContext;

    void setupSharedMem(size_t mem_size)
    {
        assert(-1 == gFileDescr);
        assert(NULL == gSharedMemoryAddr);
        assert(NULL == gSharedMemorySemaphore);

        gSharedMemorySize = mem_size;

        gFileDescr = shm_open(mem_name, O_RDWR | O_CREAT, 0);

        if (gFileDescr <= 0) {
            printf("Error, shm_open failed %d %s\n", errno, strerror(errno));
            cleanup();
            exit(-1);
        }

        if (ftruncate(gFileDescr, mem_size)) {
            printf("ftruncate failed %d %s\n", errno, strerror(errno));
            cleanup();
            exit(-1);
        }

        gSharedMemoryAddr = mmap(0, mem_size, PROT_WRITE, MAP_SHARED, gFileDescr, 0);

        if (gSharedMemoryAddr == (void *)-1) {
            gSharedMemoryAddr = NULL;
            printf("Could not map the memory: %d %s\n", errno, strerror(errno));
            cleanup();

            exit(-1);
        }

        // open a semaphore to sync memory access.
        gSharedMemorySemaphore = sem_open(sem_name, O_CREAT, 0644, 1);
        assert(gSharedMemorySemaphore);

        int semval;
        sem_getvalue(gSharedMemorySemaphore, &semval);
        printf("The value of the semaphore is: %d\n", semval);

        sem_wait(gSharedMemorySemaphore);

    }

    void cleanup()
    {
        if (gSharedMemorySemaphore)
            sem_post(gSharedMemorySemaphore);

        if (gSharedMemorySemaphore)
            sem_close(gSharedMemorySemaphore);

        if (gSharedMemoryAddr)
            munmap(gSharedMemoryAddr, gSharedMemorySize);


        shm_unlink(mem_name);
        sem_unlink(sem_name);
    }

    void askForTask(unsigned char value, completion_proc_t completionProc, void * context)
    {
        unsigned char * memptr = (unsigned char *) gSharedMemoryAddr;

        memptr[0] = value;

        CallbackAndContext * candc = (CallbackAndContext *)malloc(sizeof(CallbackAndContext));
        candc->callback = completionProc;
        candc->context = context;

        pthread_t myThread;
        pthread_create(&myThread, NULL, run_task, (void *)candc);
    }

    void * run_task(void * context)
    {
        CallbackAndContext * candc = (CallbackAndContext *)context;

        completion_proc_t comp_proc = NULL;
        void * callback_context = NULL;

        if (candc) {
            comp_proc = candc->callback;
            callback_context = candc->context;

            free(candc);
        }




        printf("My Task runner started.\n");

        // this will cause the task to start.
        if (sem_post(gSharedMemorySemaphore)) {
            printf("Error posting to semaphore: %d %s\n", errno, strerror(errno));
            cleanup();
            exit(-1);
        }

        // wait for task to be done.
        if (sem_wait(gSharedMemorySemaphore)) {
            printf("Error acquiring semaphore: %d %s\n", errno, strerror(errno));
            cleanup();
            exit(-1);
        }



        printf("Task over\n");
        if (comp_proc) {
            comp_proc(callback_context);
        }

        return NULL;
    }

在我的main.mm文件中,它看起来像这样:

    #define SHARED_MEMORY_BLOCK_SIZE 5000

    unsigned char gValue = 0;

    extern void * gSharedMemoryAddr;

    NSConditionLock * taskLock;
    enum {
         waiting
        ,done
    };

    void MyCompletionProc(void * context)
    {
        assert(gSharedMemoryAddr);
        unsigned char * valPtr = (unsigned char *)gSharedMemoryAddr;

        printf("Task Complete Callback: %s\n", gValue == valPtr[1] ? "success" : "fail" );



        [taskLock lock];
        [taskLock unlockWithCondition:done];
    }

    int main(int argc, const char * argv[])
    {
        taskLock = [[NSConditionLock alloc] initWithCondition: waiting];

        setupSharedMem(SHARED_MEMORY_BLOCK_SIZE);

        NSDate * start_time = [NSDate date];

        for (;[[NSDate date] timeIntervalSinceDate:start_time] < 30.0f;) {

            askForTask(++gValue, MyCompletionProc, NULL);
            [taskLock lockWhenCondition:done];
            [taskLock unlockWithCondition:waiting];
            sleep(1);

        }

        cleanup();

        return 0;
    }

(希望将Objective-C混合在一起不会让人感到困惑。)

我第一次运行该程序似乎可以正常调用askTask一次。 30秒后,它会调用“清理”并退出。

在后续运行中(除非我更改mem_name / sem_name的名称),我收到权限错误。当我重新启动计算机直到下一次时它就消失了。

我做错了什么,如何“重置”或阻止它进入这种状态?

跟进:看来shm_unlink在cleanup()中失败并且权限被拒绝。我不知道为什么。

1 个答案:

答案 0 :(得分:4)

解决。

问题是,当调用shm_open时,您需要指定一个“模式”,为用户提供访问共享内存的权限 - 否则在取消链接时会出现权限错误。

gFileDescr = shm_open(mem_name, O_RDWR | O_CREAT, 0);


gFileDescr = shm_open(mem_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

我在这里找到答案:https://groups.google.com/forum/#!topic/native-client-reviews/EHHHfK_xPZ4