mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			161 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
    This file is part of TON Blockchain Library.
 | 
						|
 | 
						|
    TON Blockchain Library is free software: you can redistribute it and/or modify
 | 
						|
    it under the terms of the GNU Lesser General Public License as published by
 | 
						|
    the Free Software Foundation, either version 2 of the License, or
 | 
						|
    (at your option) any later version.
 | 
						|
 | 
						|
    TON Blockchain Library is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
    GNU Lesser General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU Lesser General Public License
 | 
						|
    along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
    Copyright 2017-2020 Telegram Systems LLP
 | 
						|
*/
 | 
						|
#pragma once
 | 
						|
 | 
						|
#include "td/utils/port/config.h"
 | 
						|
 | 
						|
#include "td/utils/common.h"
 | 
						|
#include "td/utils/Status.h"
 | 
						|
 | 
						|
#if TD_PORT_POSIX
 | 
						|
#include <pthread.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <memory>
 | 
						|
 | 
						|
namespace td {
 | 
						|
 | 
						|
class RwMutex {
 | 
						|
 public:
 | 
						|
  RwMutex() {
 | 
						|
    init();
 | 
						|
  }
 | 
						|
  RwMutex(const RwMutex &) = delete;
 | 
						|
  RwMutex &operator=(const RwMutex &) = delete;
 | 
						|
  RwMutex(RwMutex &&other) {
 | 
						|
    init();
 | 
						|
    other.clear();
 | 
						|
  }
 | 
						|
  RwMutex &operator=(RwMutex &&other) {
 | 
						|
    other.clear();
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  ~RwMutex() {
 | 
						|
    clear();
 | 
						|
  }
 | 
						|
 | 
						|
  bool empty() const {
 | 
						|
    return !is_valid_;
 | 
						|
  }
 | 
						|
 | 
						|
  void init();
 | 
						|
 | 
						|
  void clear();
 | 
						|
 | 
						|
  struct ReadUnlock {
 | 
						|
    void operator()(RwMutex *ptr) {
 | 
						|
      ptr->unlock_read_unsafe();
 | 
						|
    }
 | 
						|
  };
 | 
						|
  struct WriteUnlock {
 | 
						|
    void operator()(RwMutex *ptr) {
 | 
						|
      ptr->unlock_write_unsafe();
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  using ReadLock = std::unique_ptr<RwMutex, ReadUnlock>;
 | 
						|
  using WriteLock = std::unique_ptr<RwMutex, WriteUnlock>;
 | 
						|
 | 
						|
  Result<ReadLock> lock_read() TD_WARN_UNUSED_RESULT {
 | 
						|
    lock_read_unsafe();
 | 
						|
    return ReadLock(this);
 | 
						|
  }
 | 
						|
 | 
						|
  Result<WriteLock> lock_write() TD_WARN_UNUSED_RESULT {
 | 
						|
    lock_write_unsafe();
 | 
						|
    return WriteLock(this);
 | 
						|
  }
 | 
						|
 | 
						|
  void lock_read_unsafe();
 | 
						|
 | 
						|
  void lock_write_unsafe();
 | 
						|
 | 
						|
  void unlock_read_unsafe();
 | 
						|
 | 
						|
  void unlock_write_unsafe();
 | 
						|
 | 
						|
 private:
 | 
						|
  bool is_valid_ = false;
 | 
						|
#if TD_PORT_POSIX
 | 
						|
  pthread_rwlock_t mutex_;
 | 
						|
#elif TD_PORT_WINDOWS
 | 
						|
  unique_ptr<SRWLOCK> mutex_;
 | 
						|
#endif
 | 
						|
};
 | 
						|
 | 
						|
inline void RwMutex::init() {
 | 
						|
  CHECK(empty());
 | 
						|
  is_valid_ = true;
 | 
						|
#if TD_PORT_POSIX
 | 
						|
  pthread_rwlock_init(&mutex_, nullptr);
 | 
						|
#elif TD_PORT_WINDOWS
 | 
						|
  mutex_ = make_unique<SRWLOCK>();
 | 
						|
  InitializeSRWLock(mutex_.get());
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
inline void RwMutex::clear() {
 | 
						|
  if (is_valid_) {
 | 
						|
#if TD_PORT_POSIX
 | 
						|
    pthread_rwlock_destroy(&mutex_);
 | 
						|
#elif TD_PORT_WINDOWS
 | 
						|
    mutex_.release();
 | 
						|
#endif
 | 
						|
    is_valid_ = false;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
inline void RwMutex::lock_read_unsafe() {
 | 
						|
  CHECK(!empty());
 | 
						|
// TODO error handling
 | 
						|
#if TD_PORT_POSIX
 | 
						|
  pthread_rwlock_rdlock(&mutex_);
 | 
						|
#elif TD_PORT_WINDOWS
 | 
						|
  AcquireSRWLockShared(mutex_.get());
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
inline void RwMutex::lock_write_unsafe() {
 | 
						|
  CHECK(!empty());
 | 
						|
#if TD_PORT_POSIX
 | 
						|
  pthread_rwlock_wrlock(&mutex_);
 | 
						|
#elif TD_PORT_WINDOWS
 | 
						|
  AcquireSRWLockExclusive(mutex_.get());
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
inline void RwMutex::unlock_read_unsafe() {
 | 
						|
  CHECK(!empty());
 | 
						|
#if TD_PORT_POSIX
 | 
						|
  pthread_rwlock_unlock(&mutex_);
 | 
						|
#elif TD_PORT_WINDOWS
 | 
						|
  ReleaseSRWLockShared(mutex_.get());
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
inline void RwMutex::unlock_write_unsafe() {
 | 
						|
  CHECK(!empty());
 | 
						|
#if TD_PORT_POSIX
 | 
						|
  pthread_rwlock_unlock(&mutex_);
 | 
						|
#elif TD_PORT_WINDOWS
 | 
						|
  ReleaseSRWLockExclusive(mutex_.get());
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace td
 |