Ticket #2657: draft-shm-001.patch

File draft-shm-001.patch, 19.3 KB (added by 0xffea, 13 years ago)
  • new file headers/posix/sys/shm.h

    From 6e58174c10ee548fe7e9e67d26e80c63d2590815 Mon Sep 17 00:00:00 2001
    From: David Hoeppner <dhoeppne@golem.(none)>
    Date: Sun, 26 Dec 2010 18:58:43 +0100
    Subject: [PATCH] sys/shm.h
    
    ---
     headers/posix/sys/shm.h                          |   41 ++
     headers/private/kernel/posix/xsi_shared_memory.h |   29 ++
     headers/private/system/syscalls.h                |    7 +
     src/system/kernel/main.cpp                       |    2 +
     src/system/kernel/posix/Jamfile                  |    1 +
     src/system/kernel/posix/xsi_shared_memory.cpp    |  456 ++++++++++++++++++++++
     src/system/kernel/syscalls.cpp                   |    1 +
     src/system/libroot/posix/sys/Jamfile             |    1 +
     src/system/libroot/posix/sys/xsi_shm.cpp         |   48 +++
     src/tests/system/libroot/posix/Jamfile           |    1 +
     src/tests/system/libroot/posix/xsi_shm_test1.cpp |   92 +++++
     11 files changed, 679 insertions(+), 0 deletions(-)
     create mode 100644 headers/posix/sys/shm.h
     create mode 100644 headers/private/kernel/posix/xsi_shared_memory.h
     create mode 100644 src/system/kernel/posix/xsi_shared_memory.cpp
     create mode 100644 src/system/libroot/posix/sys/xsi_shm.cpp
     create mode 100644 src/tests/system/libroot/posix/xsi_shm_test1.cpp
    
    diff --git a/headers/posix/sys/shm.h b/headers/posix/sys/shm.h
    new file mode 100644
    index 0000000..d51f52f
    - +  
     1/*
     2 * Copyright 2010 Haiku Inc. All Rights Reserved.
     3 * Distributed under the terms of the MIT License.
     4 */
     5#ifndef _SYS_SHM_H
     6#define _SYS_SHM_H
     7
     8
     9#include <sys/ipc.h>
     10#include <sys/types.h>
     11
     12#define SHMLBA      1024
     13
     14/* Message Flags */
     15#define SHM_RDONLY  01000   /* attach read-only (else read-write) */
     16#define SHM_RND     02000   /* rounds attach address to SHMLBA */
     17
     18typedef unsigned long shmatt_t;
     19
     20struct shmid_ds {
     21    struct ipc_perm shm_perm;
     22    size_t      shm_segsz;
     23    pid_t       shm_lpid;
     24    pid_t       shm_cpid;
     25    shmatt_t    shm_nattch;
     26    time_t      shm_atime;
     27    time_t      shm_dtime;
     28    time_t      shm_ctime;
     29};
     30
     31
     32__BEGIN_DECLS
     33
     34void*   shmat(int, const void *, int);
     35int shmctl(int, int, struct shmid_ds *);
     36int shmdt(const void *);
     37int shmget(key_t, size_t, int);
     38
     39__END_DECLS
     40
     41#endif  /* _SYS_SHM_H */
  • new file headers/private/kernel/posix/xsi_shared_memory.h

    diff --git a/headers/private/kernel/posix/xsi_shared_memory.h b/headers/private/kernel/posix/xsi_shared_memory.h
    new file mode 100644
    index 0000000..f237fce
    - +  
     1/*
     2 * Copyright 2010, Haiku Inc. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 */
     5
     6#ifndef KERNEL_XSI_SHARED_MEMORY_H
     7#define KERNEL_XSI_SHARED_MEMORY_H
     8
     9#include <sys/shm.h>
     10#include <sys/cdefs.h>
     11
     12#include <OS.h>
     13
     14#include <kernel.h>
     15
     16
     17__BEGIN_DECLS
     18
     19extern void xsi_shm_init();
     20
     21/* user calls */
     22status_t    _user_xsi_shmat(int, const void*, int, void**);
     23int _user_xsi_shmctl(int, int, struct shmid_ds *);
     24int _user_xsi_shmdt(const void *);
     25int _user_xsi_shmget(key_t key, size_t size, int flags);
     26
     27__END_DECLS
     28
     29#endif  /* KERNEL_XSI_SHARED_MEMORY_H */
  • headers/private/system/syscalls.h

    diff --git a/headers/private/system/syscalls.h b/headers/private/system/syscalls.h
    index 42e6d57..01f2b39 100644
    a b struct _sem_t;  
    3535struct sembuf;
    3636union semun;
    3737struct sigaction;
     38struct shmid_ds;
    3839struct stat;
    3940struct system_profiler_parameters;
    4041
    extern int _kern_xsi_msgsnd(int messageQueueID,  
    125126                        const void *messagePointer, size_t messageSize,
    126127                        int messageFlags);
    127128
     129/* POSIX XSI shared memory syscalls */
     130extern status_t     _kern_xsi_shmat(int a, const void* memoryPointer, int b, void **addr);
     131extern int      _kern_xsi_shmctl(int a, int b, struct shmid_ds *memoryDs);
     132extern int      _kern_xsi_shmdt(const void *memoryPointer);
     133extern int      _kern_xsi_shmget(key_t key, size_t size, int flags);
     134
    128135/* team & thread syscalls */
    129136extern thread_id    _kern_load_image(const char* const* flatArgs,
    130137                        size_t flatArgsSize, int32 argCount, int32 envCount,
  • src/system/kernel/main.cpp

    diff --git a/src/system/kernel/main.cpp b/src/system/kernel/main.cpp
    index eca43c7..649e0a2 100644
    a b  
    4242#include <posix/realtime_sem.h>
    4343#include <posix/xsi_message_queue.h>
    4444#include <posix/xsi_semaphore.h>
     45#include <posix/xsi_shared_memory.h>
    4546#include <real_time_clock.h>
    4647#include <sem.h>
    4748#include <smp.h>
    _start(kernel_args *bootKernelArgs, int currentCPU)  
    190191        realtime_sem_init();
    191192        xsi_sem_init();
    192193        xsi_msg_init();
     194        xsi_shm_init();
    193195
    194196        // Start a thread to finish initializing the rest of the system. Note,
    195197        // it won't be scheduled before calling scheduler_start() (on any CPU).
  • src/system/kernel/posix/Jamfile

    diff --git a/src/system/kernel/posix/Jamfile b/src/system/kernel/posix/Jamfile
    index 1eb2f51..ffb2f38 100644
    a b KernelMergeObject kernel_posix.o :  
    66    realtime_sem.cpp
    77    xsi_message_queue.cpp
    88    xsi_semaphore.cpp
     9    xsi_shared_memory.cpp
    910
    1011    : $(TARGET_KERNEL_PIC_CCFLAGS)
    1112;
  • new file src/system/kernel/posix/xsi_shared_memory.cpp

    diff --git a/src/system/kernel/posix/xsi_shared_memory.cpp b/src/system/kernel/posix/xsi_shared_memory.cpp
    new file mode 100644
    index 0000000..875c9a8
    - +  
     1/*
     2 * Copyright 2011, Haiku Inc. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Authors:
     6 *      David Höppner <0xffea@gmail.com>
     7 */
     8
     9#include <posix/xsi_shared_memory.h>
     10
     11#include <stdio.h>
     12
     13#include <sys/ipc.h>
     14#include <sys/types.h>
     15
     16#include <kernel/lock.h>
     17#include <kernel/debug.h>
     18#include <kernel/team.h>
     19#include <kernel/thread.h>
     20
     21#include <vm/vm.h>
     22#include <vm/VMAddressSpace.h>
     23#include <vm/VMArea.h>
     24
     25#include <util/AutoLock.h>
     26#include <util/DoublyLinkedList.h>
     27#include <util/OpenHashTable.h>
     28
     29
     30#define TRACE_XSI_SHM
     31#ifdef TRACE_XSI_SHM
     32#   define TRACE(x)     dprintf x
     33#else
     34#   define TRACE(x)     /* nothing */
     35#endif
     36
     37#define MAX_XSI_SHARED_MEMORY_COUNT 64
     38#define MIN_XSI_SHARED_MEMORY_SIZE  1
     39#define MAX_XSI_SHARED_MEMORY_SIZE  256*1024*1024
     40#define MAX_XSI_SHARED_MEMORY_ATTACH    128
     41
     42static mutex sXsiSharedMemoryLock = MUTEX_INITIALIZER("Global Shared Memory Lock");
     43static int sSharedMemoryCount = 0;
     44static int sNextEntryID = 0;
     45
     46struct SharedMemoryKey : DoublyLinkedListLinkImpl<SharedMemoryKey> {
     47    SharedMemoryKey(key_t key, int id, size_t size)
     48        :
     49        key(key),
     50        id(id),
     51        size(size)
     52    {
     53    }
     54
     55    key_t   key;
     56    int id;
     57    size_t  size;
     58};
     59
     60typedef DoublyLinkedList<SharedMemoryKey> SharedMemoryKeyList;
     61static SharedMemoryKeyList sSharedMemoryKeys;
     62
     63
     64class SharedMemoryEntry {
     65public:
     66    SharedMemoryEntry(key_t key, size_t size, int flags)
     67        :
     68        fKey(key),
     69        fSize(size),
     70        fKeyLink(NULL)
     71    {
     72        fDs.shm_segsz = fSize;
     73
     74        fDs.shm_cpid = getpid();
     75        fDs.shm_lpid = fDs.shm_nattch = 0;
     76        fDs.shm_atime = fDs.shm_dtime = 0;
     77        fDs.shm_ctime = real_time_clock();
     78
     79        fDs.shm_perm.uid = fDs.shm_perm.cuid = geteuid();
     80        fDs.shm_perm.gid = fDs.shm_perm.cgid = getegid();
     81        fDs.shm_perm.mode = (flags & 0x01ff);
     82    }
     83
     84    status_t Init()
     85    {
     86        char    areaName[B_OS_NAME_LENGTH];
     87        addr_t  dummy;
     88
     89        fId = sNextEntryID;
     90
     91        snprintf(areaName, B_OS_NAME_LENGTH, "xsi_shared_memory%d", (int) fId);
     92
     93        virtual_address_restrictions virtualRestrictions = {};
     94        virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
     95        physical_address_restrictions physicalRestrictions = {};
     96        fArea = vm_create_anonymous_area(B_SYSTEM_TEAM, areaName, fSize, B_FULL_LOCK,
     97            B_KERNEL_AREA_FLAGS, 0, &virtualRestrictions, &physicalRestrictions,
     98            true, (void **) &dummy);
     99
     100        if (fArea < B_OK) {
     101            TRACE(("xsi_shmget: create area failed!\n"));
     102            return B_NO_MEMORY;
     103        }
     104
     105        memset((void*)dummy, 0, fSize);
     106
     107        atomic_add(&sNextEntryID, 1);
     108        atomic_add(&sSharedMemoryCount, 1);
     109
     110        return B_OK;
     111    }
     112
     113    ~SharedMemoryEntry()
     114    {
     115        status_t status;
     116
     117        status = vm_delete_area(B_SYSTEM_TEAM, fArea, true);
     118        if (status < B_OK)
     119            TRACE(("shmctl: failed to delete area %d\n", (int) fArea));
     120
     121        atomic_add(&sSharedMemoryCount, -1);
     122    }
     123
     124    void SetKey()
     125    {
     126        fKey = sNextEntryID;
     127    }
     128
     129    void SetKeyLink(SharedMemoryKey* key)
     130    {
     131        fKeyLink = key;
     132    }
     133
     134    bool HasPermission() const
     135    {
     136
     137        uid_t uid = geteuid();
     138        if (uid == 0 ||
     139            uid == fDs.shm_perm.uid ||
     140            uid == fDs.shm_perm.cuid)
     141            return true;
     142
     143        return false;
     144    }
     145
     146    bool HasReadPermission() const
     147    {
     148        if (fDs.shm_perm.mode & S_IROTH)
     149            return true;
     150
     151        uid_t uid = geteuid();
     152        if (uid == 0 || (uid == fDs.shm_perm.uid
     153            && (fDs.shm_perm.mode & S_IRUSR) != 0))
     154            return true;
     155
     156                gid_t gid = getegid();
     157                if (uid == 0 || (gid == fDs.shm_perm.gid
     158                        && (fDs.shm_perm.mode & S_IRGRP) != 0))
     159                        return true;
     160
     161        return false;
     162    }
     163
     164    int Id() const
     165    {
     166        return fId;
     167    }
     168
     169    key_t Key() const
     170    {
     171        return fKey;
     172    }
     173
     174    area_id Area() const
     175    {
     176        return fArea;
     177    }
     178
     179    size_t Size() const
     180    {
     181        return fSize;
     182    }
     183
     184    SharedMemoryKey* KeyLink() const
     185    {
     186        return fKeyLink;
     187    }
     188
     189    struct shmid_ds* GetDs()
     190    {
     191        return &fDs;
     192    }   
     193
     194    SharedMemoryEntry*& Link()
     195    {
     196        return fLink;
     197    }
     198
     199private:
     200    int         fId;
     201    key_t           fKey;
     202    area_id         fArea;
     203    size_t          fSize;
     204    SharedMemoryKey*    fKeyLink;
     205    SharedMemoryEntry*  fLink;
     206    struct shmid_ds     fDs;
     207};
     208
     209struct XsiSharedMemoryEntryHashTableDefinition {
     210    typedef int         KeyType;
     211    typedef SharedMemoryEntry   ValueType;
     212
     213    size_t HashKey (const int id) const
     214    {
     215        return (size_t)(id);
     216    }
     217
     218    size_t Hash(SharedMemoryEntry* variable) const
     219    {
     220        return (size_t) HashKey(variable->Id());
     221    }
     222
     223    bool Compare(const int id, SharedMemoryEntry* variable) const
     224    {
     225        return (int) id == (int) variable->Id();
     226    }
     227
     228    SharedMemoryEntry*& GetLink(SharedMemoryEntry* variable) const
     229    {
     230        return variable->Link();
     231    }
     232};
     233
     234static BOpenHashTable<XsiSharedMemoryEntryHashTableDefinition> sSharedMemoryEntryTable;
     235
     236
     237void
     238xsi_shm_init()
     239{
     240    status_t status;
     241
     242    status = sSharedMemoryEntryTable.Init();
     243    if (status != B_OK) {
     244        panic("xsi_shm_init(): Failed to initialize shared memory hash table!\n");
     245    }
     246
     247    new(&sSharedMemoryKeys) SharedMemoryKeyList;
     248}
     249
     250status_t
     251_user_xsi_shmat(int id, const void *addr, int flags, void **raddr)
     252{
     253    SharedMemoryEntry* entry;
     254    struct shmid_ds* mds;
     255    struct area_info info;
     256    void* address;
     257    uint32 addressSpec = B_ANY_ADDRESS;
     258    area_id area;
     259    int protection = B_READ_AREA | B_WRITE_AREA;
     260
     261    TRACE(("shmat: id = %d, addr = %p, flags = %d\n",
     262        id, addr, flags));
     263
     264    MutexLocker _(sXsiSharedMemoryLock);
     265
     266    entry = sSharedMemoryEntryTable.Lookup(id);
     267    if (entry == NULL)
     268        return EINVAL;
     269
     270
     271    mds = entry->GetDs();
     272    if (mds->shm_nattch >= MAX_XSI_SHARED_MEMORY_ATTACH)
     273        return EMFILE;
     274
     275    if (flags & SHM_RDONLY)
     276        protection &= ~B_WRITE_AREA;
     277
     278    if (addr != NULL) {
     279        if (flags & SHM_RND) {
     280            // TODO address = (void *) (addr - ((uintptr_t) addr % SHMLBA));
     281            return EINVAL;
     282        } else {
     283            if (!IS_USER_ADDRESS(addr))
     284                return B_BAD_ADDRESS;
     285
     286            address = (void *) addr;
     287            addressSpec = B_EXACT_ADDRESS;
     288        }
     289
     290        if (!IS_USER_ADDRESS(address))
     291            return B_BAD_ADDRESS;
     292    }
     293
     294    get_area_info(entry->Area(), &info);
     295    area = vm_clone_area(VMAddressSpace::CurrentID(), info.name, &address, addressSpec,
     296            protection, REGION_NO_PRIVATE_MAP, entry->Area(), false);
     297
     298    if (area < B_OK)
     299        return area;
     300
     301    mds->shm_atime = real_time_clock();
     302    mds->shm_nattch++;
     303
     304    *raddr = address;
     305
     306    return B_OK;
     307}
     308
     309int
     310_user_xsi_shmctl(int id, int cmd, struct shmid_ds* buffer)
     311{
     312    SharedMemoryEntry *entry;
     313    struct shmid_ds* mds;
     314    status_t status;
     315
     316    TRACE(("shmctl: id = %d, cmd = %d\n", id, cmd));
     317
     318    MutexLocker _(sXsiSharedMemoryLock);
     319
     320    entry = sSharedMemoryEntryTable.Lookup(id);
     321    if (entry == NULL)
     322        return EINVAL;
     323
     324    switch(cmd) {
     325        case IPC_STAT:
     326            if (!entry->HasReadPermission())
     327                return EACCES;
     328
     329            if (!IS_USER_ADDRESS(buffer))
     330                return B_BAD_ADDRESS;
     331
     332            // TODO: EOVERFLOW
     333            mds = (struct shmid_ds*)entry->GetDs();
     334            status = user_memcpy(buffer, (const void*) mds, sizeof(struct shmid_ds));
     335            if (status < B_OK) {
     336                return B_BAD_ADDRESS;
     337            }
     338            break;
     339        case IPC_SET:
     340            if (!entry->HasPermission())
     341                return EPERM;
     342
     343            if (!IS_USER_ADDRESS(buffer))
     344                return B_BAD_ADDRESS;
     345
     346            mds = entry->GetDs();
     347            status = user_memcpy(mds, buffer, sizeof(struct shmid_ds));
     348            if (status < B_OK)
     349                return B_BAD_ADDRESS;
     350
     351            break;
     352        case IPC_RMID:
     353            if (!entry->HasPermission())
     354                return EPERM;
     355
     356            sSharedMemoryKeys.Remove(entry->KeyLink());
     357            sSharedMemoryEntryTable.Remove(entry);
     358            delete entry;
     359
     360            break;
     361        default:
     362            return EINVAL;
     363    }
     364
     365    return B_OK;
     366}
     367
     368int
     369_user_xsi_shmdt(const void *address)
     370{
     371    area_id     area;
     372    status_t    status;
     373
     374    TRACE(("xsi_shmdt: %p\n", address));
     375
     376    area = area_for((void*)address);
     377    if (area == B_ERROR)
     378        return EINVAL;
     379
     380    status = vm_delete_area(VMAddressSpace::CurrentID(), area, true);
     381    if (status < B_OK) {
     382        return EINVAL;
     383    }
     384
     385    MutexLocker _(sXsiSharedMemoryLock);
     386    // TODO nattch
     387   
     388    return B_OK;
     389}
     390
     391int
     392_user_xsi_shmget(key_t key, size_t size, int flags)
     393{
     394    SharedMemoryEntry* entry;
     395    SharedMemoryKey* keyEntry = NULL;
     396    status_t status;
     397
     398    TRACE(("shmget: key = %d, size = %d, flags = %d\n",
     399        (int) key, (int) size, flags));
     400
     401    MutexLocker _(sXsiSharedMemoryLock);
     402
     403    if (key != IPC_PRIVATE) {
     404        SharedMemoryKeyList::Iterator it = sSharedMemoryKeys.GetIterator();
     405
     406        while (it.HasNext()) {
     407            keyEntry = it.Next();
     408
     409            if (keyEntry->key == key) {
     410                if ((flags & IPC_CREAT) && (flags & IPC_EXCL))
     411                    return EEXIST;
     412
     413                if (keyEntry->size < size && size != 0)
     414                    return EINVAL;
     415
     416                return keyEntry->id;
     417            }
     418        }
     419
     420        if (!(flags & IPC_CREAT))
     421            return ENOENT;
     422    }
     423
     424        if (size < MIN_XSI_SHARED_MEMORY_SIZE ||
     425                size > MAX_XSI_SHARED_MEMORY_SIZE)
     426                return EINVAL;
     427
     428    if (sSharedMemoryCount > MAX_XSI_SHARED_MEMORY_COUNT)
     429        return ENOSPC;
     430
     431    entry = new (std::nothrow) SharedMemoryEntry(key, size, flags);
     432    if (entry == NULL)
     433        return ENOMEM;
     434
     435
     436    status = entry->Init();
     437    if (status < B_OK) {
     438        delete entry;
     439        return status;
     440    }
     441
     442    if (key != IPC_PRIVATE) {
     443        keyEntry = new(std::nothrow) SharedMemoryKey(key, entry->Id(), size);
     444        if (keyEntry == NULL) {
     445            delete entry;
     446            return ENOMEM;
     447        }
     448
     449        sSharedMemoryKeys.Add(keyEntry);
     450        entry->SetKeyLink(keyEntry);
     451    }
     452
     453    sSharedMemoryEntryTable.Insert(entry);
     454
     455    return entry->Id();
     456}
  • src/system/kernel/syscalls.cpp

    diff --git a/src/system/kernel/syscalls.cpp b/src/system/kernel/syscalls.cpp
    index b8efd95..4c90658 100644
    a b  
    3838#include <posix/realtime_sem.h>
    3939#include <posix/xsi_message_queue.h>
    4040#include <posix/xsi_semaphore.h>
     41#include <posix/xsi_shared_memory.h>
    4142#include <real_time_clock.h>
    4243#include <safemode.h>
    4344#include <sem.h>
  • src/system/libroot/posix/sys/Jamfile

    diff --git a/src/system/libroot/posix/sys/Jamfile b/src/system/libroot/posix/sys/Jamfile
    index 17601c8..40f0d0a 100644
    a b MergeObject posix_sys.o :  
    2626    wait.c
    2727    xsi_msg_queue.cpp
    2828    xsi_sem.cpp
     29    xsi_shm.cpp
    2930;
  • new file src/system/libroot/posix/sys/xsi_shm.cpp

    diff --git a/src/system/libroot/posix/sys/xsi_shm.cpp b/src/system/libroot/posix/sys/xsi_shm.cpp
    new file mode 100644
    index 0000000..8632463
    - +  
     1/*
     2 * Copyright 2010, Haiku Inc. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Authors:
     6 *      David Höppner <0xffea@gmail.com>
     7 */
     8
     9#include <errno.h>
     10
     11#include <sys/shm.h>
     12
     13#include <syscall_utils.h>
     14#include <syscalls.h>
     15
     16
     17void *
     18shmat(int key, const void *address, int flags)
     19{
     20    status_t status;
     21    void *addr;
     22
     23    status = _kern_xsi_shmat(key, address, flags, &addr);
     24    if (status < 0) {
     25        errno = status;
     26        return (void *) -1;
     27    }
     28
     29    return (void *) addr;
     30}
     31
     32int
     33shmctl(int id, int cmd, struct shmid_ds *buffer)
     34{
     35    RETURN_AND_SET_ERRNO(_kern_xsi_shmctl(id, cmd, buffer));
     36}
     37
     38int
     39shmdt(const void *address)
     40{
     41    RETURN_AND_SET_ERRNO(_kern_xsi_shmdt(address));
     42}
     43
     44int
     45shmget(key_t key, size_t size, int flags)
     46{
     47    RETURN_AND_SET_ERRNO(_kern_xsi_shmget(key, size, flags));
     48}
  • src/tests/system/libroot/posix/Jamfile

    diff --git a/src/tests/system/libroot/posix/Jamfile b/src/tests/system/libroot/posix/Jamfile
    index aced757..1a97ba4 100644
    a b SimpleTest init_rld_after_fork_test : init_rld_after_fork_test.cpp ;  
    3333# XSI tests
    3434SimpleTest xsi_msg_queue_test1 : xsi_msg_queue_test1.cpp ;
    3535SimpleTest xsi_sem_test1 : xsi_sem_test1.cpp ;
     36SimpleTest xsi_shm_test1 : xsi_shm_test1.cpp ;
    3637
    3738# wide character tests
    3839SimpleTest mbtest : mbtest.c ;
  • new file src/tests/system/libroot/posix/xsi_shm_test1.cpp

    diff --git a/src/tests/system/libroot/posix/xsi_shm_test1.cpp b/src/tests/system/libroot/posix/xsi_shm_test1.cpp
    new file mode 100644
    index 0000000..cdbfba6
    - +  
     1/*
     2 * Copyright 2008-2011, Haiku Inc. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Authors:
     6 *      Salvatore Benedetto <salvatore.benedetto@gmail.com>
     7 *      David Höppner <0xffea@gmail.com>
     8 */
     9
     10#include <errno.h>
     11#include <stdio.h>
     12#include <stdlib.h>
     13#include <string.h>
     14#include <unistd.h>
     15#include <sys/mman.h>
     16#include <sys/shm.h>
     17#include <sys/time.h>
     18#include <sys/wait.h>
     19#include <time.h>
     20
     21#include <OS.h>
     22
     23#include "TestUnitUtils.h"
     24
     25#define KEY     ((key_t)12345)
     26#define SHM_SIZE    16*1024*1024
     27
     28static void
     29test_shmget()
     30{
     31    TEST_SET("shmget({IPC_PRIVATE, key})");
     32
     33    const char* currentTest = NULL;
     34
     35    // Open private set with IPC_PRIVATE
     36    TEST("shmget(IPC_PRIVATE) - private");
     37    int shmID = shmget(IPC_PRIVATE, SHM_SIZE, S_IRUSR | S_IWUSR);
     38    assert_posix_bool_success(shmID != -1);
     39
     40    // Destroy private memory entry
     41    TEST("shmctl(IPC_RMID) - private");
     42    status_t status = shmctl(shmID, IPC_RMID, NULL);
     43    assert_posix_bool_success(status != -1);
     44
     45    // Open non-private non-existing set with IPC_CREAT
     46    TEST("shmget(KEY, IPC_CREAT) non-existing");
     47    shmID = shmget(KEY, SHM_SIZE, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR
     48        | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
     49    assert_posix_bool_success(status != -1);
     50
     51    // Re-open non-private existing with greater size
     52    TEST("shmget(KEY) re-open existing without IPC_CREAT");
     53    int returnID = shmget(KEY, SHM_SIZE+1, 0);
     54    assert_posix_bool_success(errno == EINVAL);
     55
     56    // Re-open non-private existing without IPC_CREAT
     57    TEST("shmget(KEY) re-open existing without IPC_CREAT");
     58    returnID = shmget(KEY, SHM_SIZE, 0);
     59    assert_equals(shmID, returnID);
     60
     61    // Re-open non-private existing with IPC_CREAT
     62    TEST("shmget(IPC_CREATE) re-open existing with IPC_CREAT");
     63    returnID = shmget(KEY, SHM_SIZE, IPC_CREAT | IPC_EXCL);
     64    assert_posix_bool_success(errno == EEXIST);
     65
     66    // Destroy non-private
     67    TEST("shmctl(IPC_RMID)");
     68    status = shmctl(shmID, IPC_RMID, NULL);
     69    assert_posix_bool_success(status != -1);
     70
     71    // Open non-private non-existing without IPC_CREAT
     72    TEST("shmget(IPC_CREATE) non-existing without IPC_CREAT");
     73    shmID = shmget(KEY, SHM_SIZE, IPC_EXCL | S_IRUSR | S_IWUSR
     74        | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
     75    assert_posix_bool_success(errno == ENOENT);
     76
     77    // Destroy non-existing
     78    TEST("shmctl()");
     79    status = shmctl(shmID, IPC_RMID, NULL);
     80    assert_posix_bool_success(errno == EINVAL);
     81
     82    TEST("done");
     83}
     84
     85
     86int
     87main()
     88{
     89    test_shmget();
     90
     91    printf("\nAll tests OK\n");
     92}