Browse Source

Rework shared memory utils, add tests

tags/1.9.4
falkTX 11 years ago
parent
commit
a0487f1d41
2 changed files with 255 additions and 94 deletions
  1. +120
    -20
      source/tests/CarlaUtils.cpp
  2. +135
    -74
      source/utils/CarlaShmUtils.hpp

+ 120
- 20
source/tests/CarlaUtils.cpp View File

@@ -36,6 +36,8 @@
#include "CarlaLv2Utils.hpp"
#include "CarlaVstUtils.hpp"

#include "CarlaShmUtils.hpp"

// used in dssi utils
#include "juce_core.h"
#include <QtCore/QDir>
@@ -46,17 +48,7 @@
// #include "CarlaJuceUtils.hpp"
// #include "CarlaLibUtils.hpp"
// #include "CarlaOscUtils.hpp"
// #include "CarlaShmUtils.hpp"
// #include "CarlaStateUtils.hpp"
// #include "CarlaVstUtils.hpp"

// #include "CarlaLibCounter.hpp"
// #include "CarlaLogThread.hpp"
// #include "CarlaRingBuffer.hpp"
// #include "CarlaThread.hpp"
// #include "Lv2AtomQueue.hpp"

// #include "JucePluginWindow.hpp"

#if 0
// -----------------------------------------------------------------------
@@ -594,7 +586,6 @@ static void test_CarlaLv2Utils() noexcept
is_lv2_feature_supported("test1");
is_lv2_ui_feature_supported("test2");
}
#endif

// -----------------------------------------------------------------------

@@ -613,6 +604,111 @@ static void test_CarlaVstUtils() noexcept
carla_stdout(vstEffectOpcode2str(effOpen));
carla_stdout(vstMasterOpcode2str(audioMasterAutomate));
}
#endif

// -----------------------------------------------------------------------

struct ShmStruct {
char stringStart[255];
bool boolean;
int integer;
float floating;
char stringEnd[255];
};

static void test_CarlaShmUtils() noexcept
{
shm_t shm, shma;
ShmStruct* shmStruct1;
ShmStruct* shmStruct2;

// base tests first
carla_shm_init(shm);
assert(! carla_is_shm_valid(shm));

shm = carla_shm_create("/carla-shm-test1");
carla_stdout("test %i", shm);
assert(carla_is_shm_valid(shm));

carla_shm_close(shm);
assert(! carla_is_shm_valid(shm));

shm = carla_shm_create("/carla-shm-test1");
assert(carla_is_shm_valid(shm));

shma = carla_shm_attach("/carla-shm-test1");
assert(carla_is_shm_valid(shma));

carla_shm_close(shm);
carla_shm_close(shma);
assert(! carla_is_shm_valid(shm));
assert(! carla_is_shm_valid(shma));

// test attach invalid
shma = carla_shm_attach("/carla-shm-test-NOT");
assert(! carla_is_shm_valid(shma));

// test memory, start
shm = carla_shm_create("/carla-shm-test1");
assert(carla_is_shm_valid(shm));

shma = carla_shm_attach("/carla-shm-test1");
assert(carla_is_shm_valid(shma));

// test memory, check valid
shmStruct1 = carla_shm_map<ShmStruct>(shm);
assert(shmStruct1 != nullptr);

shmStruct2 = carla_shm_map<ShmStruct>(shma);
assert(shmStruct2 != nullptr);

carla_shm_unmap(shma, shmStruct2);
assert(shmStruct2 == nullptr);

carla_shm_unmap(shm, shmStruct1);
assert(shmStruct1 == nullptr);

// test memory, check if write data matches
shmStruct1 = carla_shm_map<ShmStruct>(shm);
assert(shmStruct1 != nullptr);

shmStruct2 = carla_shm_map<ShmStruct>(shma);
assert(shmStruct2 != nullptr);

carla_zeroStruct(*shmStruct1);
assert(shmStruct1->stringStart[0] == '\0');
assert(shmStruct2->stringStart[0] == '\0');
assert(shmStruct1->stringEnd[0] == '\0');
assert(shmStruct2->stringEnd[0] == '\0');
assert(! shmStruct1->boolean);
assert(! shmStruct2->boolean);

shmStruct1->boolean = true;
shmStruct1->integer = 232312;
assert(shmStruct1->boolean == shmStruct2->boolean);
assert(shmStruct1->integer == shmStruct2->integer);

shmStruct2->floating = 2342.231f;
std::strcpy(shmStruct2->stringStart, "test1start");
std::strcpy(shmStruct2->stringEnd, "test2end");
assert(shmStruct1->floating == shmStruct2->floating);
assert(std::strcmp(shmStruct1->stringStart, "test1start") == 0);
assert(std::strcmp(shmStruct1->stringStart, shmStruct2->stringStart) == 0);
assert(std::strcmp(shmStruct1->stringEnd, "test2end") == 0);
assert(std::strcmp(shmStruct1->stringEnd, shmStruct2->stringEnd) == 0);

carla_shm_unmap(shma, shmStruct2);
assert(shmStruct2 == nullptr);

carla_shm_unmap(shm, shmStruct1);
assert(shmStruct1 == nullptr);

// test memory, done
carla_shm_close(shm);
carla_shm_close(shma);
assert(! carla_is_shm_valid(shm));
assert(! carla_is_shm_valid(shma));
}

// -----------------------------------------------------------------------
// main
@@ -620,16 +716,20 @@ static void test_CarlaVstUtils() noexcept
int main()
{
// already tested, skip for now
// test_CarlaUtils();
// test_CarlaMathUtils();
//
// test_CarlaBackendUtils();
// test_CarlaEngineUtils();
//
// test_CarlaLadspaUtils();
// test_CarlaDssiUtils();
// test_CarlaLv2Utils();
#if 0
test_CarlaUtils();
test_CarlaMathUtils();

test_CarlaBackendUtils();
test_CarlaEngineUtils();

test_CarlaLadspaUtils();
test_CarlaDssiUtils();
test_CarlaLv2Utils();
test_CarlaVstUtils();
#endif

test_CarlaShmUtils();

return 0;
}


+ 135
- 74
source/utils/CarlaShmUtils.hpp View File

@@ -25,169 +25,230 @@ struct shm_t { HANDLE shm; HANDLE map; };
#else
# include <fcntl.h>
# include <sys/mman.h>
typedef int shm_t;
struct shm_t { int fd; const char* filename; };
#endif

// -----------------------------------------------------------------------
// shared memory calls

/*
* Null object returned when a shared memory operation fails.
*/
#ifdef CARLA_OS_WIN
static const shm_t gNullCarlaShm = { nullptr, nullptr };
#else
static const shm_t gNullCarlaShm = -1;
static const shm_t gNullCarlaShm = { -1, nullptr };
#endif

// -----------------------------------------------------------------------
// shared memory calls
/*
* Initialize a shared memory object to an invalid state.
*/
static inline
bool carla_is_shm_valid(const shm_t& shm) noexcept
void carla_shm_init(shm_t& shm) noexcept
{
#ifdef CARLA_OS_WIN
return (shm.shm != nullptr && shm.shm != INVALID_HANDLE_VALUE);
shm.shm = nullptr;
shm.map = nullptr;
#else
return (shm >= 0);
shm.fd = -1;
shm.filename = nullptr;
#endif
}

/*
* Check if a shared memory object is valid.
*/
static inline
void carla_shm_init(shm_t& shm) noexcept
bool carla_is_shm_valid(const shm_t& shm) noexcept
{
#ifdef CARLA_OS_WIN
shm.shm = nullptr;
shm.map = nullptr;
return (shm.shm != nullptr && shm.shm != INVALID_HANDLE_VALUE);
#else
shm = -1;
return (shm.fd >= 0);
#endif
}

#ifdef CARLA_OS_WIN
/*
* Create and open a new shared memory object.
* Returns an invalid object if the operation failed or the filename already exists.
*/
static inline
shm_t carla_shm_create(const char* const name)
shm_t carla_shm_create(const char* const filename) noexcept
{
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', gNullCarlaShm);
CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', gNullCarlaShm);

shm_t ret;
ret.shm = nullptr; // TODO
ret.map = nullptr;

try {
#ifdef CARLA_OS_WIN
ret.shm = nullptr; // TODO
ret.map = nullptr;
#else
ret.fd = ::shm_open(filename, O_CREAT|O_EXCL|O_RDWR, 0600);
ret.filename = (ret.fd >= 0) ? carla_strdup(filename) : nullptr;
#endif
}
catch(...) {
carla_safe_exception("carla_shm_create", __FILE__, __LINE__);
ret = gNullCarlaShm;
}

return ret;
}

/*
* Attach to an existing shared memory object.
*/
static inline
shm_t carla_shm_attach(const char* const name)
shm_t carla_shm_attach(const char* const filename) noexcept
{
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', gNullCarlaShm);
CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', gNullCarlaShm);

shm_t ret;
ret.shm = ::CreateFileA(name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
ret.map = nullptr;

return ret;
}
try {
#ifdef CARLA_OS_WIN
ret.shm = ::CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
ret.map = nullptr;
#else
static inline
shm_t carla_shm_create(const char* const name)
{
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', gNullCarlaShm);

return ::shm_open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
}

static inline
shm_t carla_shm_attach(const char* const name)
{
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', gNullCarlaShm);
ret.fd = ::shm_open(filename, O_RDWR, 0);
ret.filename = nullptr;
#endif
}
catch(...) {
ret = gNullCarlaShm;
}

return ::shm_open(name, O_RDWR, 0);
return ret;
}
#endif

/*
* Close a shared memory object and invalidate it.
*/
static inline
void carla_shm_close(shm_t& shm)
void carla_shm_close(shm_t& shm) noexcept
{
CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm),);

#ifdef CARLA_OS_WIN
CARLA_SAFE_ASSERT(shm.map == nullptr);
#endif

::CloseHandle(shm.shm);
shm.shm = nullptr;
try {
#ifdef CARLA_OS_WIN
::CloseHandle(shm.shm);
#else
::close(shm);
shm = -1;
::close(shm.fd);

if (shm.filename != nullptr)
{
::shm_unlink(shm.filename);
delete[] shm.filename;
}
#endif
} CARLA_SAFE_EXCEPTION("carla_shm_close");

shm = gNullCarlaShm;
}

/*
* Map a shared memory object to @a size bytes and returns its address.
* @note One shared memory object can only have one mapping at a time.
*/
static inline
void* carla_shm_map(shm_t& shm, const size_t size)
void* carla_shm_map(shm_t& shm, const size_t size) noexcept
{
CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm), nullptr);
CARLA_SAFE_ASSERT_RETURN(size > 0, nullptr);

#ifdef CARLA_OS_WIN
CARLA_SAFE_ASSERT_RETURN(shm.map == nullptr, nullptr);
#endif

HANDLE map = ::CreateFileMapping(shm.shm, NULL, PAGE_READWRITE, size, size, NULL);

CARLA_SAFE_ASSERT_RETURN(map != nullptr, nullptr);

HANDLE ptr = ::MapViewOfFile(map, FILE_MAP_COPY, 0, 0, size);
try {
#ifdef CARLA_OS_WIN
const HANDLE map = ::CreateFileMapping(shm.shm, NULL, PAGE_READWRITE, size, size, NULL);
CARLA_SAFE_ASSERT_RETURN(map != nullptr, nullptr);

if (ptr == nullptr)
{
::CloseHandle(map);
return nullptr;
}
HANDLE ptr = ::MapViewOfFile(map, FILE_MAP_COPY, 0, 0, size);

shm.map = map;
if (ptr == nullptr)
{
carla_safe_assert("ptr != nullptr", __FILE__, __LINE__);
::CloseHandle(map);
return nullptr;
}

return ptr;
shm.map = map;
return ptr;
#else
if (::ftruncate(shm, static_cast<off_t>(size)) != 0)
return nullptr;
const int ret = ::ftruncate(shm.fd, static_cast<off_t>(size));
CARLA_SAFE_ASSERT_RETURN(ret == 0, nullptr);

return ::mmap(nullptr, size, PROT_READ|PROT_WRITE, MAP_SHARED, shm, 0);
return ::mmap(nullptr, size, PROT_READ|PROT_WRITE, MAP_SHARED, shm.fd, 0);
#endif
} CARLA_SAFE_EXCEPTION_RETURN("carla_shm_map", nullptr);
}

/*
* Unmap a shared memory object address.
*/
static inline
void carla_shm_unmap(shm_t& shm, void* const ptr, const size_t size)
void carla_shm_unmap(shm_t& shm, void* const ptr, const size_t size) noexcept
{
CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm),);
CARLA_SAFE_ASSERT_RETURN(ptr != nullptr,);
CARLA_SAFE_ASSERT_RETURN(size > 0,);

#ifdef CARLA_OS_WIN
CARLA_SAFE_ASSERT_RETURN(shm.map != nullptr,);
#endif

::UnmapViewOfFile(ptr);
::CloseHandle(shm.map);
shm.map = nullptr;
return;
try {
#ifdef CARLA_OS_WIN
const Handle map = shm.map;
shm.map = nullptr;

// unused
(void)size;
::UnmapViewOfFile(ptr);
::CloseHandle(map);
#else
::munmap(ptr, size);
return;
const int ret = ::munmap(ptr, size);
CARLA_SAFE_ASSERT(ret == 0);
#endif
} CARLA_SAFE_EXCEPTION("carla_shm_unmap");

// unused
return; // unused depending on platform
(void)shm;
#endif
(void)size;
}

// -----------------------------------------------------------------------
// shared memory, templated calls

/*
* Map a shared memory object, handling object type and size.
*/
template<typename T>
static inline
T* carla_shm_map(shm_t& shm) noexcept
{
return (T*)carla_shm_map(shm, sizeof(T));
}

/*
* Map a shared memory object and return if it's non-null.
*/
template<typename T>
static inline
bool carla_shm_map(shm_t& shm, T*& value)
bool carla_shm_map(shm_t& shm, T*& value) noexcept
{
value = (T*)carla_shm_map(shm, sizeof(T));
return (value != nullptr);
}

/*
* Unmap a shared memory object address and set it as null.
*/
template<typename T>
static inline
void carla_shm_unmap(shm_t& shm, T*& value)
void carla_shm_unmap(shm_t& shm, T*& value) noexcept
{
carla_shm_unmap(shm, value, sizeof(T));
value = nullptr;


Loading…
Cancel
Save