inline void priv_open_or_create()

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);
    }
  }