in Cthulhu/src/boost/interprocess/detail/managed_open_or_create_impl_ashmem.hpp [201:358]
inline void priv_open_or_create(
create_enum_t type,
const device_id_t& id,
std::size_t size,
mode_t mode,
const void* addr,
ConstructFunc construct_func) {
typedef bool_<FileBased> file_like_t;
(void)mode;
bool created = false;
bool ronly = false;
bool cow = false;
DeviceAbstraction dev;
if (type != DoOpen) {
// Check if the requested size is enough to build the managed metadata
const std::size_t func_min_size = construct_func.get_min_size();
if ((std::size_t(-1) - ManagedOpenOrCreateUserOffset) < func_min_size ||
size < (func_min_size + ManagedOpenOrCreateUserOffset)) {
throw interprocess_exception(error_info(size_error));
}
}
// Check size can be represented by offset_t (used by truncate)
if (type != DoOpen && !check_offset_t_size<FileBased>(size, file_like_t())) {
throw interprocess_exception(error_info(size_error));
}
if (type == DoOpen && mode == read_write) {
DeviceAbstraction tmp(open_only, id, read_write);
tmp.swap(dev);
created = false;
} else if (type == DoOpen && mode == read_only) {
DeviceAbstraction tmp(open_only, id, read_only);
tmp.swap(dev);
created = false;
ronly = true;
} else if (type == DoOpen && mode == copy_on_write) {
DeviceAbstraction tmp(open_only, id, read_only);
tmp.swap(dev);
created = false;
cow = true;
} else if (type == DoCreate) {
create_device<FileBased>(dev, id, size, file_like_t());
created = true;
} else if (type == DoOpenOrCreate) {
// This loop is very ugly, but brute force is sometimes better
// than diplomacy. If someone knows how to open or create a
// file and know if we have really created it or just open it
// drop me a e-mail!
bool completed = false;
spin_wait swait;
while (!completed) {
try {
create_device<FileBased>(dev, id, size, file_like_t());
created = true;
completed = true;
} catch (interprocess_exception& ex) {
if (ex.get_error_code() != already_exists_error) {
throw;
} else {
try {
DeviceAbstraction tmp(open_only, id, read_write);
dev.swap(tmp);
created = false;
completed = true;
} catch (interprocess_exception& e) {
if (e.get_error_code() != not_found_error) {
throw;
}
} catch (...) {
throw;
}
}
} catch (...) {
throw;
}
swait.yield();
}
}
if (created) {
try {
// If this throws, we are lost
truncate_device<FileBased>(dev, size, file_like_t());
// If the following throws, we will truncate the file to 1
mapped_region region(dev, read_write, 0, size, addr);
boost::uint32_t* patomic_word = 0; // avoid gcc warning
patomic_word = static_cast<boost::uint32_t*>(region.get_address());
boost::uint32_t previous =
atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);
if (previous == UninitializedSegment) {
try {
construct_func(
static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset,
size - ManagedOpenOrCreateUserOffset,
true);
// All ok, just move resources to the external mapped region
m_mapped_region.swap(region);
} catch (...) {
atomic_write32(patomic_word, CorruptedSegment);
throw;
}
atomic_write32(patomic_word, InitializedSegment);
} else if (previous == InitializingSegment || previous == InitializedSegment) {
throw interprocess_exception(error_info(already_exists_error));
} else {
throw interprocess_exception(error_info(corrupted_error));
}
} catch (...) {
try {
truncate_device<FileBased>(dev, 1u, file_like_t());
} catch (...) {
}
throw;
}
} else {
if (FileBased) {
offset_t filesize = 0;
spin_wait swait;
while (filesize == 0) {
if (!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)) {
error_info err = system_error_code();
throw interprocess_exception(err);
}
swait.yield();
}
if (filesize == 1) {
throw interprocess_exception(error_info(corrupted_error));
}
}
mapped_region region(
dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, size, addr);
boost::uint32_t* patomic_word = static_cast<boost::uint32_t*>(region.get_address());
boost::uint32_t value = atomic_read32(patomic_word);
spin_wait swait;
while (value == InitializingSegment || value == UninitializedSegment) {
swait.yield();
value = atomic_read32(patomic_word);
}
if (value != InitializedSegment)
throw interprocess_exception(error_info(corrupted_error));
construct_func(
static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset,
region.get_size() - ManagedOpenOrCreateUserOffset,
false);
// All ok, just move resources to the external mapped region
m_mapped_region.swap(region);
}
if (StoreDevice) {
this->DevHolder::get_device() = boost::move(dev);
}
}