// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: morlovich@google.com (Maksim Orlovich)

#include "pagespeed/kernel/thread/pthread_shared_mem.h"

#include <fcntl.h>
#include <pthread.h>
#include <sys/mman.h>
#include <unistd.h>
#include <cerrno>
#include <cstddef>
#include <map>
#include <utility>

#include "base/logging.h"
#include "pagespeed/kernel/base/abstract_shared_mem.h"
#include "pagespeed/kernel/base/abstract_mutex.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/message_handler.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"

namespace net_instaweb {

namespace {

// This implementation relies on readonly copies of old memory and shared R/W
// mappings being kept across a fork. It simply stashes addresses of
// shared mmap segments into a map where kid processes can pick them up.

// close() a fd logging failure and dealing with EINTR.
void CheckedClose(int fd, MessageHandler* message_handler) {
  while (close(fd) != 0) {
    if (errno != EINTR) {
      message_handler->Message(kWarning, "Problem closing SHM segment fd:%d",
                               errno);
      return;
    }
  }
}

// Unlike PthreadMutex this doesn't own the lock, but rather refers to an
// external one.
class PthreadSharedMemMutex : public AbstractMutex {
 public:
  explicit PthreadSharedMemMutex(pthread_mutex_t* external_mutex)
      : external_mutex_(external_mutex) {}

  virtual bool TryLock() {
    return (pthread_mutex_trylock(external_mutex_) == 0);
  }

  virtual void Lock() {
    pthread_mutex_lock(external_mutex_);
  }

  virtual void Unlock() {
    pthread_mutex_unlock(external_mutex_);
  }

 private:
  pthread_mutex_t* external_mutex_;

  DISALLOW_COPY_AND_ASSIGN(PthreadSharedMemMutex);
};

class PthreadSharedMemSegment : public AbstractSharedMemSegment {
 public:
  // We will be representing memory mapped in the [base, base + size) range.
  PthreadSharedMemSegment(char* base, size_t size, MessageHandler* handler)
      : base_(base),
        size_(size) {
  }

  virtual ~PthreadSharedMemSegment() {
  }

  virtual volatile char* Base() {
    return base_;
  }

  virtual size_t SharedMutexSize() const {
    return sizeof(pthread_mutex_t);
  }

  virtual bool InitializeSharedMutex(size_t offset, MessageHandler* handler) {
    pthread_mutexattr_t attr;
    if (pthread_mutexattr_init(&attr) != 0) {
      handler->Message(kError, "pthread_mutexattr_init failed with errno:%d",
                       errno);
      return false;
    }

    if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) != 0) {
      pthread_mutexattr_destroy(&attr);
      handler->Message(
          kError, "pthread_mutexattr_setpshared failed with errno:%d", errno);
      return false;
    }

    if (pthread_mutex_init(MutexPtr(offset), &attr) != 0) {
      pthread_mutexattr_destroy(&attr);
      handler->Message(kError, "pthread_mutex_init failed with errno:%d",
                       errno);
      return false;
    }

    pthread_mutexattr_destroy(&attr);
    return true;
  }

  virtual AbstractMutex* AttachToSharedMutex(size_t offset) {
    return new PthreadSharedMemMutex(MutexPtr(offset));
  }

 private:
  pthread_mutex_t* MutexPtr(size_t offset) {
    return reinterpret_cast<pthread_mutex_t*>(base_ + offset);
  }

  char* const base_;
  const size_t size_;

  DISALLOW_COPY_AND_ASSIGN(PthreadSharedMemSegment);
};

pthread_mutex_t segment_bases_lock = PTHREAD_MUTEX_INITIALIZER;

}  // namespace

size_t PthreadSharedMem::s_instance_count_ = 0;

PthreadSharedMem::SegmentBaseMap* PthreadSharedMem::segment_bases_ = NULL;

PthreadSharedMem::PthreadSharedMem() {
  instance_number_ = ++s_instance_count_;
}

PthreadSharedMem::~PthreadSharedMem() {
}

size_t PthreadSharedMem::SharedMutexSize() const {
  return sizeof(pthread_mutex_t);
}

AbstractSharedMemSegment* PthreadSharedMem::CreateSegment(
    const GoogleString& name, size_t size, MessageHandler* handler) {
  GoogleString prefixed_name = PrefixSegmentName(name);
  // Create the memory
  int fd = open("/dev/zero", O_RDWR);
  if (fd == -1) {
    handler->Message(
        kError, "Unable to create SHM segment %s, open of /dev/zero failed "
        "with errno=%d.", prefixed_name.c_str(), errno);
    return NULL;
  }

  // map it
  char* base = reinterpret_cast<char*>(
                   mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
  int mmap_errno = errno;
  CheckedClose(fd, handler);
  if (base == MAP_FAILED) {
    handler->Message(
        kError, "Unable to create SHM segment %s, mmap failed with errno=%d.",
        prefixed_name.c_str(), mmap_errno);
    return NULL;
  }

  SegmentBaseMap* bases = AcquireSegmentBases();
  (*bases)[prefixed_name] = std::make_pair(base, size);
  UnlockSegmentBases();
  return new PthreadSharedMemSegment(base, size, handler);
}

AbstractSharedMemSegment* PthreadSharedMem::AttachToSegment(
    const GoogleString& name, size_t size, MessageHandler* handler) {
  GoogleString prefixed_name = PrefixSegmentName(name);
  SegmentBaseMap* bases = AcquireSegmentBases();
  SegmentBaseMap::const_iterator i = bases->find(prefixed_name);
  if (i == bases->end()) {
    handler->Message(kError, "Unable to find SHM segment %s to attach to.",
                     prefixed_name.c_str());
    UnlockSegmentBases();
    return NULL;
  }
  char* base = i->second.first;
  DCHECK_EQ(size, i->second.second);
  UnlockSegmentBases();
  return new PthreadSharedMemSegment(base, size, handler);
}

void PthreadSharedMem::DestroySegment(const GoogleString& name,
                                      MessageHandler* handler) {
  GoogleString prefixed_name = PrefixSegmentName(name);
  // Note that in the process state children will not see any mutations
  // we make here, so it acts mostly for checking in that case.
  SegmentBaseMap* bases = AcquireSegmentBases();
  SegmentBaseMap::iterator i = bases->find(prefixed_name);
  if (i != bases->end()) {
    // Note that we must munmap the segment here in order to not leak like crazy
    // for things like apache2ctrl graceful (and similar nginx configuration).
    munmap(i->second.first, i->second.second);
    bases->erase(i);
    if (bases->empty()) {
      delete segment_bases_;
      segment_bases_ = NULL;
    }
  } else {
    handler->Message(kError, "Attempt to destroy unknown SHM segment %s.",
                     prefixed_name.c_str());
  }
  UnlockSegmentBases();
}

PthreadSharedMem::SegmentBaseMap* PthreadSharedMem::AcquireSegmentBases() {
  PthreadSharedMemMutex lock(&segment_bases_lock);
  lock.Lock();

  if (segment_bases_ == NULL) {
    segment_bases_ = new SegmentBaseMap();
  }

  return segment_bases_;
}

void PthreadSharedMem::UnlockSegmentBases() {
  PthreadSharedMemMutex lock(&segment_bases_lock);
  lock.Unlock();
}

GoogleString PthreadSharedMem::PrefixSegmentName(const GoogleString& name) {
  GoogleString res;
  StrAppend(&res, "[", IntegerToString(instance_number_), "]", name);
  return res;
}

void PthreadSharedMem::Terminate() {
  // Clean up the local memory associated with the maps to shared memory
  // storage.
  PthreadSharedMemMutex lock(&segment_bases_lock);
  lock.Lock();
  if (segment_bases_ != NULL) {
    delete segment_bases_;
    segment_bases_ = NULL;
  }
  lock.Unlock();
}

}  // namespace net_instaweb
