├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── examples ├── CMakeLists.txt ├── echo │ ├── CMakeLists.txt │ └── echo.cc └── simple │ ├── CMakeLists.txt │ └── simple.cc └── tin ├── all.h ├── bufio ├── buffered_reader.cc ├── buffered_reader.h ├── bufio.cc └── bufio.h ├── communication ├── chan.h └── queue.h ├── config ├── config.cc ├── config.h └── default.h ├── error ├── error.h ├── error_inl.h ├── error_posix.cc └── error_windows.cc ├── io ├── io.cc ├── io.h ├── io_buffer.cc └── io_buffer.h ├── net ├── address_family.cc ├── address_family.h ├── address_list.cc ├── address_list.h ├── dialer.cc ├── dialer.h ├── fd_mutex.cc ├── fd_mutex.h ├── inet.cc ├── inet.h ├── ip_address.cc ├── ip_address.h ├── ip_endpoint.cc ├── ip_endpoint.h ├── listener.cc ├── listener.h ├── net.cc ├── net.h ├── netfd.h ├── netfd_common.cc ├── netfd_common.h ├── netfd_posix.cc ├── netfd_posix.h ├── netfd_windows.cc ├── netfd_windows.h ├── poll_desc.cc ├── poll_desc.h ├── resolve.cc ├── resolve.h ├── sockaddr_storage.cc ├── sockaddr_storage.h ├── sys_addrinfo.h ├── sys_socket.h ├── tcp_conn.cc ├── tcp_conn.h ├── winsock_util.cc └── winsock_util.h ├── platform ├── platform.h ├── platform_posix.cc ├── platform_posix.h ├── platform_win.cc └── platform_win.h ├── runtime ├── env.cc ├── env.h ├── greenlet.cc ├── greenlet.h ├── guintptr.h ├── m.cc ├── m.h ├── net │ ├── netpoll.cc │ ├── netpoll.h │ ├── netpoll_epoll.cc │ ├── netpoll_kqueue.cc │ ├── netpoll_windows.cc │ ├── poll_descriptor.cc │ ├── poll_descriptor.h │ ├── pollops.cc │ └── pollops.h ├── os_posix.cc ├── os_win.cc ├── p.cc ├── p.h ├── posix_util.cc ├── posix_util.h ├── raw_mutex.h ├── raw_mutex_sema.cc ├── runtime.cc ├── runtime.h ├── scheduler.cc ├── scheduler.h ├── semaphore.cc ├── semaphore.h ├── spawn.h ├── spin.cc ├── spin.h ├── stack │ ├── fixedsize_stack.cc │ ├── fixedsize_stack.h │ ├── protected_fixedsize_stack.h │ ├── protected_fixedsize_stack_posix.cc │ ├── protected_fixedsize_stack_win.cc │ ├── stack.cc │ └── stack.h ├── sysmon.cc ├── sysmon.h ├── threadpoll.cc ├── threadpoll.h ├── timer │ ├── timer_queue.cc │ └── timer_queue.h ├── unlock.cc ├── unlock.h ├── util.cc └── util.h ├── sync ├── atomic.h ├── atomic_flag.h ├── cond.cc ├── cond.h ├── mutex.cc ├── mutex.h ├── rwmutex.cc ├── rwmutex.h ├── wait_group.cc └── wait_group.h ├── time ├── time.cc └── time.h ├── tin.cc ├── tin.h └── util ├── unique_id.cc └── unique_id.h /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "third_party/base03"] 2 | path = third_party/base03 3 | url = https://github.com/cloudpeak/base03.git 4 | [submodule "third_party/quark"] 5 | path = third_party/quark 6 | url = https://github.com/cloudpeak/quark.git 7 | [submodule "third_party/zcontext"] 8 | path = third_party/zcontext 9 | url = https://github.com/cloudpeak/zcontext.git 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2021, cloudpeak 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Platforms 3 | + Windows XP or later 4 | + OS X 10.8 or later 5 | + Linux 2.6.23 or later 6 | 7 | # How to build 8 | + git clone --recursive https://github.com/cloudpeak/tin.git 9 | + cd tin 10 | + mkdir build 11 | + cd build 12 | + Visual studio 13 | + Visual Studio 2022 Win64 14 | + cmake -G "Visual Studio 17 2022" -A x64 ../ -DCMAKE_BUILD_TYPE=RELEASE 15 | + Visual Studio 2019 Win64 16 | + cmake -G "Visual Studio 16 2019" -A x64 ../ -DCMAKE_BUILD_TYPE=RELEASE 17 | 18 | + Visual Studio 2015 Win64 19 | + cmake -G "Visual Studio 14 2015 Win64" ../ -DCMAKE_BUILD_TYPE=RELEASE 20 | 21 | + Visual Studio 2015 Win32 22 | + cmake -G "Visual Studio 14 2015" ../ -DCMAKE_BUILD_TYPE=RELEASE 23 | 24 | + Visual Studio 2008 Win32 25 | + cmake -G "Visual Studio 9 2008" ../ -DCMAKE_BUILD_TYPE=RELEASE 26 | 27 | + GCC or Clang 28 | + cmake ../ -DCMAKE_BUILD_TYPE=RELEASE && make 29 | 30 | ## Example(echo server) 31 | ```c++ 32 | #include "tin/all.h" 33 | 34 | void HandleClient(tin::net::TcpConn conn) { 35 | // Set TCP Read Write buffer. 36 | conn->SetReadBuffer(64 * 1024); 37 | conn->SetWriteBuffer(64 * 1024); 38 | 39 | // user space buffer size. 40 | const int kIOBufferSize = 4 * 1024; 41 | scoped_ptr buf(new char[kIOBufferSize]); 42 | 43 | // set read, write deadline. 44 | const int64_t kRWDeadline = 20 * tin::kSecond; 45 | conn->SetDeadline(kRWDeadline); 46 | while (true) { 47 | int n = conn->Read(buf.get(), kIOBufferSize); 48 | int err = tin::GetErrorCode(); 49 | if (n > 0) { 50 | conn->SetReadDeadline(kRWDeadline); 51 | } 52 | if (err != 0) { 53 | VLOG(1) << "Read failed due to: " << tin::GetErrorStr(); 54 | // FIN received, graceful close, we can still send. 55 | if (err == TIN_EOF) { 56 | if (n > 0) { 57 | conn->Write(buf.get(), n); 58 | } 59 | conn->CloseWrite(); 60 | // delay a while to avoid RST. 61 | tin::NanoSleep(500 * tin::kMillisecond); 62 | } 63 | break; 64 | } 65 | DCHECK_GT(n, 0); 66 | conn->Write(buf.get(), n); 67 | if (tin::GetErrorCode() != 0) { 68 | VLOG(1) << "Write failed due to " << tin::GetErrorStr(); 69 | break; 70 | } 71 | conn->SetWriteDeadline(kRWDeadline); 72 | } 73 | conn->Close(); 74 | } 75 | 76 | int TinMain(int argc, char** argv) { 77 | const uint16 kPort = 2222; 78 | bool use_ipv6 = false; 79 | tin::net::TCPListener listener = 80 | tin::net::ListenTcp(use_ipv6 ? "0:0:0:0:0:0:0:0" : "0.0.0.0", kPort); 81 | if (tin::GetErrorCode() != 0) { 82 | LOG(FATAL) << "Listen failed due to " << tin::GetErrorStr(); 83 | } 84 | LOG(INFO) << "echo server is listening on port: " << kPort; 85 | while (true) { 86 | tin::net::TcpConn conn = listener->Accept(); 87 | if (tin::GetErrorCode() == 0) { 88 | tin::Spawn(&HandleClient, conn); 89 | } else { 90 | LOG(INFO) << "Accept failed due to " << tin::GetErrorStr(); 91 | } 92 | } 93 | return 0; 94 | } 95 | 96 | int main(int argc, char** argv) { 97 | tin::Initialize(); 98 | 99 | // set logging level. 100 | logging::SetMinLogLevel(logging::LOG_INFO); 101 | 102 | // set max p count. 103 | tin::Config config = tin::DefaultConfig(); 104 | config.SetMaxProcs(base::SysInfo::NumberOfProcessors()); 105 | 106 | // start the world. 107 | tin::PowerOn(TinMain, argc, argv, &config); 108 | 109 | // wait for power off 110 | tin::WaitForPowerOff(); 111 | 112 | // cleanup. 113 | tin::Deinitialize(); 114 | 115 | return 0; 116 | } 117 | 118 | 119 | ``` 120 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(APPLE) 2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -framework Cocoa") 3 | endif() 4 | 5 | add_subdirectory(simple) 6 | set_property(TARGET simple PROPERTY FOLDER "examples") 7 | 8 | add_subdirectory(echo) 9 | set_property(TARGET echo PROPERTY FOLDER "examples") 10 | 11 | -------------------------------------------------------------------------------- /examples/echo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(echo echo.cc) 2 | target_link_libraries(echo ${DEP_LIBS}) -------------------------------------------------------------------------------- /examples/simple/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(simple simple.cc) 2 | target_link_libraries(simple ${DEP_LIBS}) -------------------------------------------------------------------------------- /examples/simple/simple.cc: -------------------------------------------------------------------------------- 1 | #include "tin/all.h" 2 | 3 | int TinMain(int argc, char** argv) { 4 | LOG(INFO) << "TinMain"; 5 | return 0; 6 | } 7 | 8 | int main(int argc, char** argv) { 9 | tin::Initialize(); 10 | 11 | // set logging level. 12 | logging::SetMinLogLevel(-1); 13 | 14 | // set max p count. 15 | tin::Config config = tin::DefaultConfig(); 16 | config.SetMaxProcs(base::SysInfo::NumberOfProcessors()); 17 | 18 | // start the world. 19 | tin::PowerOn(TinMain, argc, argv, &config); 20 | 21 | // wait for power off 22 | tin::WaitForPowerOff(); 23 | 24 | // cleanup. 25 | tin::Deinitialize(); 26 | 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /tin/all.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #ifndef _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS 8 | #define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS 9 | #endif 10 | 11 | #include 12 | #include 13 | 14 | #include "tin/net/sys_socket.h" 15 | 16 | #include "cliff/base/sys_byteorder.h" 17 | 18 | #include "tin/error/error.h" 19 | #include "tin/time/time.h" 20 | #include "tin/communication/chan.h" 21 | #include "tin/net/resolve.h" 22 | #include "tin/net/dialer.h" 23 | #include "tin/net/netfd.h" 24 | #include "tin/sync/atomic_flag.h" 25 | #include "tin/sync/atomic.h" 26 | #include "tin/sync/mutex.h" 27 | #include "tin/sync/wait_group.h" 28 | #include "tin/runtime/spawn.h" 29 | #include "tin/runtime/runtime.h" 30 | 31 | #include "tin/tin.h" 32 | 33 | #include 34 | 35 | -------------------------------------------------------------------------------- /tin/bufio/buffered_reader.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include "tin/error/error.h" 7 | #include "tin/runtime/runtime.h" 8 | 9 | #include "tin/bufio/buffered_reader.h" 10 | 11 | namespace tin { 12 | 13 | BufferedReader::BufferedReader(tin::io::Reader* reader, int size) 14 | : buffer_(size) 15 | , last_read_(0) 16 | , reader_(reader) 17 | , total_bytes_stat_(0) { 18 | } 19 | 20 | bool BufferedReader::ReadFull(int n) { 21 | DCHECK_GT(n, 0); 22 | buffer_.AdvanceReadablePtr(last_read_); 23 | last_read_ = 0; 24 | int err = 0; 25 | if (buffer_.buffered() < n) { 26 | int lack = n - buffer_.buffered(); 27 | int bytes_free = buffer_.free(); 28 | if (bytes_free < lack) { 29 | buffer_.ReserveMore(lack); 30 | } 31 | 32 | DCHECK(reader_ != NULL); 33 | while (buffer_.buffered() < n) { 34 | char* write_ptr = NULL; 35 | int write_size = 0; 36 | buffer_.GetWritablePtr(&write_ptr, &write_size); 37 | DCHECK_GT(write_size, 0); 38 | int nread = reader_->Read(write_ptr, write_size); 39 | DCHECK_GE(nread, 0); 40 | buffer_.AdvanceWritablePtr(nread); 41 | err = tin::GetErrorCode(); 42 | if (err != 0) { 43 | break; 44 | } 45 | } 46 | } 47 | if (buffer_.buffered() >= n) { 48 | SetErrorCode(0); 49 | err = 0; 50 | } else if (buffer_.buffered() > 0 && err == TIN_EOF) { 51 | SetErrorCode(TIN_UNEXPECTED_EOF); 52 | err = TIN_UNEXPECTED_EOF; 53 | } 54 | if (err != 0) 55 | n = 0; 56 | last_read_ = n; 57 | total_bytes_stat_ += n; 58 | return err == 0; 59 | } 60 | 61 | } // namespace tin 62 | -------------------------------------------------------------------------------- /tin/bufio/buffered_reader.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "tin/io/io.h" 12 | #include "tin/io/io_buffer.h" 13 | 14 | namespace tin { 15 | 16 | const int kDefaultBufferedReaderSpace = 4096; 17 | 18 | class BufferedReader { 19 | public: 20 | BufferedReader(tin::io::Reader* reader, 21 | int size = kDefaultBufferedReaderSpace); 22 | void SetIOReader(tin::io::Reader* reader) { 23 | reader_ = reader; 24 | } 25 | 26 | // read n or failed. 27 | bool ReadFull(int n); 28 | 29 | char* Data() { 30 | return buffer_.begin(); 31 | } 32 | 33 | int Length() const { 34 | return last_read_; 35 | } 36 | 37 | uint64_t TotalBytesStat() const { 38 | return total_bytes_stat_; 39 | } 40 | 41 | private: 42 | IOBuffer buffer_; 43 | int last_read_; 44 | tin::io::Reader* reader_; 45 | uint64_t total_bytes_stat_; 46 | }; 47 | 48 | } // namespace tin 49 | -------------------------------------------------------------------------------- /tin/bufio/bufio.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "tin/io/io.h" 12 | 13 | 14 | namespace tin::bufio { 15 | 16 | const int kDefaultReaderBufSize = 4096; 17 | 18 | /* 19 | +--------------+--------------------------------+ 20 | | | buffered | free | 21 | +--------------+--------------------+-----------+ 22 | | | 23 | v v 24 | read_idx write_idx 25 | */ 26 | 27 | class Reader : public tin::io::Reader { 28 | public: 29 | explicit Reader(tin::io::Reader* rd, size_t size = kDefaultReaderBufSize); 30 | virtual ~Reader(); 31 | 32 | // reset a new underlying reader. 33 | void Reset(tin::io::Reader* rd); 34 | 35 | virtual int Read(void* buf, int nbytes); 36 | 37 | // return error code. 38 | int ReadSlice(uint8_t delim, absl::string_view* line); 39 | 40 | // return error code. 41 | int ReadLine(absl::string_view* line, bool* is_prefix); 42 | 43 | int ReadByte(uint8_t* c); 44 | int UnreadByte(); 45 | int Peek(int n, absl::string_view* piece); 46 | 47 | // inline functions 48 | int buffered() const { return write_idx_ - read_idx_; } 49 | int free() const { return (storage_size_ - write_idx_); } 50 | 51 | bool empty() const { return read_idx_ == write_idx_; } 52 | bool full() const { 53 | return ((write_idx_ == storage_size_) && (read_idx_ != write_idx_)); 54 | } 55 | 56 | typedef uint8_t* iterator; 57 | typedef const uint8_t* const_iterator; 58 | 59 | iterator begin() { return storage_ + read_idx_; } 60 | const_iterator begin() const { return storage_ + read_idx_; } 61 | 62 | iterator end() { return storage_ + write_idx_; } 63 | const_iterator end() const { return storage_ + write_idx_; } 64 | 65 | private: 66 | int ReadErr(); 67 | void Fill(); 68 | 69 | static absl::string_view ToStringPiece(const uint8_t* p, absl::string_view::size_type n) { 70 | return {reinterpret_cast(p),n}; 71 | } 72 | 73 | private: 74 | uint8_t* storage_; 75 | int storage_size_; 76 | int read_idx_; 77 | int write_idx_; 78 | int err_; 79 | tin::io::Reader* rd_; 80 | int last_byte_; 81 | }; 82 | 83 | class Writer : public tin::io::Writer { 84 | public: 85 | virtual ~Writer() {} 86 | virtual int Write(const void* buf, int nbytes) = 0; 87 | }; 88 | 89 | 90 | 91 | } // namespace tin::bufio 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /tin/communication/chan.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include 8 | #include 9 | 10 | #include "tin/sync/atomic.h" 11 | #include "tin/runtime/raw_mutex.h" 12 | #include "tin/runtime/semaphore.h" 13 | 14 | 15 | namespace tin { 16 | const uint32_t kDefaultChanSize = 64; 17 | 18 | template 19 | class Channel 20 | : public std::enable_shared_from_this> { 21 | public: 22 | explicit Channel(uint32_t max_size = kDefaultChanSize) 23 | : max_size_(max_size) 24 | , free_space_sem_(max_size) 25 | , used_space_sem_(0) 26 | , closed_(0) { 27 | // std::cout << "Channel constructor " << rand() << std::endl; 28 | } 29 | 30 | bool Push(const T& t) { 31 | if (IsClosed()) 32 | return false; 33 | bool ok; 34 | runtime::SemAcquire(&free_space_sem_); 35 | { 36 | runtime::RawMutexGuard guard(&lock_); 37 | ok = !IsClosed(); 38 | if (ok) { 39 | queue_.push_back(t); 40 | } 41 | } 42 | if (ok) { 43 | runtime::SemRelease(&used_space_sem_); 44 | } else { 45 | runtime::SemRelease(&free_space_sem_); 46 | } 47 | return ok; 48 | } 49 | 50 | bool Pop(T* t) { 51 | if (IsClosed()) 52 | return false; 53 | bool ok; 54 | runtime::SemAcquire(&used_space_sem_); 55 | do { 56 | runtime::RawMutexGuard guard(&lock_); 57 | ok = !IsClosed(); 58 | if (ok) { 59 | *t = queue_.front(); 60 | queue_.pop_front(); 61 | } 62 | } while (0); 63 | if (ok) { 64 | runtime::SemRelease(&free_space_sem_); 65 | } else { 66 | runtime::SemRelease(&used_space_sem_); 67 | } 68 | return ok; 69 | } 70 | 71 | void Close() { 72 | if (atomic::exchange32(&closed_, 1) != 0) { 73 | // already closed. 74 | return; 75 | } 76 | std::deque queue; 77 | { 78 | runtime::RawMutexGuard guard(&lock_); 79 | std::swap(queue, queue_); 80 | } 81 | ClearQueue(queue, std::is_pointer()); 82 | runtime::SemRelease(&free_space_sem_); 83 | runtime::SemRelease(&used_space_sem_); 84 | } 85 | 86 | bool IsClosed() { 87 | return atomic::acquire_load32(&closed_) != 0; 88 | } 89 | 90 | private: 91 | void ClearQueue(std::deque& queue, std::false_type) { // NOLINT 92 | queue.clear(); 93 | } 94 | 95 | void ClearQueue(std::deque& queue, std::true_type) { // NOLINT 96 | for (typename std::deque::iterator iter = queue.begin(); 97 | iter != queue.end(); 98 | ++iter) { 99 | delete *iter; 100 | } 101 | queue.clear(); 102 | } 103 | 104 | Channel(const Channel&) = delete; 105 | Channel& operator=(const Channel&) = delete; 106 | private: 107 | uint32_t free_space_sem_; 108 | uint32_t used_space_sem_; 109 | runtime::RawMutex lock_; 110 | std::deque queue_; 111 | uint32_t max_size_; 112 | uint32_t closed_; 113 | }; 114 | 115 | template 116 | class Chan { 117 | public: 118 | explicit Chan(uint32_t max_size = kDefaultChanSize) : impl_(std::make_shared>(max_size)) {} 119 | 120 | Chan(const Chan& other) : impl_(other.impl_) { 121 | } 122 | 123 | Channel* operator->() { 124 | return impl_.get(); 125 | } 126 | 127 | private: 128 | std::shared_ptr> impl_; 129 | }; 130 | 131 | template 132 | Chan MakeChan(uint32_t max_size = kDefaultChanSize) { 133 | return Chan(max_size); 134 | } 135 | 136 | 137 | } // namespace tin 138 | -------------------------------------------------------------------------------- /tin/communication/queue.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include 8 | #include 9 | #include "tin/sync/atomic.h" 10 | #include "tin/runtime/raw_mutex.h" 11 | #include "tin/runtime/semaphore.h" 12 | #include "tin/sync/cond.h" 13 | 14 | 15 | namespace tin { 16 | 17 | const uint32_t kDefaultQueueCapacity = 64; 18 | const uint32_t kMaxQueueCapacity = kuint32max; 19 | 20 | template 21 | class QueueImpl 22 | : public std::enable_shared_from_this> { 23 | public: 24 | explicit QueueImpl(uint32_t capacity = kDefaultQueueCapacity) 25 | : capacity_(capacity) 26 | , full_waiters_(0) 27 | , empty_waiters_(0) 28 | , full_cond_(&lock_) 29 | , empty_cond_(&lock_) 30 | , closed_(false) { 31 | } 32 | 33 | QueueImpl(const QueueImpl&) = delete; 34 | QueueImpl& operator=(const QueueImpl&) = delete; 35 | 36 | bool Enqueue(const T& t, size_t* size = NULL) { 37 | MutexGuard guard(&lock_); 38 | if (closed_) 39 | return false; 40 | while (queue_.size() == capacity_) { // queue is full. 41 | full_waiters_++; 42 | // Wait will release lock automatically. 43 | full_cond_.Wait(); 44 | // Wait acquired lock automatically. 45 | full_waiters_--; 46 | if (closed_) 47 | return false; 48 | } 49 | // now, we have space to push at least one item. 50 | queue_.push_back(t); 51 | // some consumers is waiting due to empty queue. 52 | if (empty_waiters_ > 0) { 53 | // some consumers is waiting for an item. 54 | empty_cond_.Signal(); 55 | } 56 | if (size != NULL) 57 | *size = queue_.size(); 58 | return true; 59 | } 60 | 61 | bool Dequeue(T* t, size_t* size = NULL) { 62 | MutexGuard guard(&lock_); 63 | if (closed_) 64 | return false; 65 | while (queue_.size() == 0) { // queue is empty 66 | empty_waiters_++; 67 | // Wait will release lock automatically. 68 | empty_cond_.Wait(); 69 | // Wait acquired lock automatically. 70 | empty_waiters_--; 71 | if (closed_) 72 | return false; 73 | } 74 | *t = queue_.front(); 75 | queue_.pop_front(); 76 | // some producers is waiting due to full queue. 77 | if (full_waiters_ > 0) { 78 | // some producers is waiting for a slot to put item. 79 | full_cond_.Signal(); 80 | } 81 | if (size != NULL) 82 | *size = queue_.size(); 83 | return true; 84 | } 85 | 86 | void Close() { 87 | MutexGuard guard(&lock_); 88 | if (closed_) 89 | return; // already closed. 90 | closed_ = true; 91 | STLClearElements(&queue_); 92 | full_cond_.Broascast(); 93 | empty_cond_.Broascast(); 94 | } 95 | 96 | size_t Size() const { 97 | MutexGuard guard(&lock_); 98 | if (closed_) 99 | return 0; 100 | return queue_.size(); 101 | } 102 | 103 | bool Empty() const { 104 | MutexGuard guard(&lock_); 105 | if (closed_) 106 | return true; 107 | return queue_.size() == 0; 108 | } 109 | 110 | // intrusive methods, be careful! 111 | void Lock() const { 112 | lock_.Lock(); 113 | } 114 | 115 | void UnLock() const { 116 | lock_.Unlock(); 117 | } 118 | 119 | bool IsClosedLocked() const { 120 | return closed_; 121 | } 122 | 123 | std::deque* MutableQueueLocked() { 124 | return &queue_; 125 | } 126 | 127 | void NotifyConsumedLocked(int n) { 128 | while (full_waiters_ > 0 && n > 0) { 129 | full_cond_.Signal(); 130 | full_waiters_--; 131 | n--; 132 | } 133 | } 134 | 135 | ~QueueImpl() { 136 | STLClearElements(&queue_); 137 | // std::cout << "Channel destructor_______\n"; 138 | } 139 | 140 | 141 | private: 142 | mutable Mutex lock_; 143 | Cond full_cond_; // producer waiting due to queue is full. 144 | Cond empty_cond_; // consumer waiting due to queue is empty. 145 | std::deque queue_; 146 | uint32_t capacity_; 147 | int full_waiters_; 148 | int empty_waiters_; 149 | bool closed_; 150 | }; 151 | 152 | template 153 | class Queue { 154 | public: 155 | explicit Queue(uint32_t max_size = kDefaultQueueCapacity) 156 | : impl_(std::make_shared>(max_size)) { 157 | } 158 | 159 | Queue(const Queue& other) : impl_(other.impl_) { 160 | } 161 | 162 | QueueImpl* operator->() { 163 | return impl_.get(); 164 | } 165 | 166 | private: 167 | std::shared_ptr> impl_; 168 | }; 169 | 170 | template 171 | Queue MakeQueue(uint32_t max_size = kDefaultQueueCapacity) { 172 | return Queue(max_size); 173 | } 174 | 175 | } // namespace tin 176 | -------------------------------------------------------------------------------- /tin/config/config.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "tin/config/config.h" 6 | -------------------------------------------------------------------------------- /tin/config/config.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include "tin/config/default.h" 8 | 9 | namespace tin { 10 | 11 | class Config { 12 | public: 13 | int MaxProcs() const { 14 | return max_procs_; 15 | } 16 | 17 | void SetMaxProcs(int max_procs) { 18 | max_procs_ = max_procs; 19 | max_machine_ = max_procs_ * 4; 20 | } 21 | 22 | int StackSize() const { 23 | return stack_size_; 24 | } 25 | 26 | void SetStackSize(int stack_size) { 27 | stack_size_ = stack_size; 28 | } 29 | 30 | int OsThreadStackSize() const { 31 | return os_thread_stack_size_; 32 | } 33 | 34 | void SetOsThreadStackSize(int stack_size) { 35 | os_thread_stack_size_ = stack_size; 36 | } 37 | 38 | void SetIgnoreSigpipe(bool ignore) { 39 | ignore_sigpipe_ = ignore; 40 | } 41 | 42 | bool IgnoreSigpipe() const { 43 | return ignore_sigpipe_; 44 | } 45 | 46 | int MaxOSMachines() const { 47 | return max_machine_; 48 | } 49 | 50 | void SetMaxMachines(int max_machine) { 51 | max_machine_ = max_machine; 52 | } 53 | 54 | bool IsStackProtectionEnabled() const { 55 | return enable_stack_protection_; 56 | } 57 | 58 | void EnableStackPprotection(bool enable) { 59 | enable_stack_protection_ = enable; 60 | } 61 | 62 | private: 63 | int max_procs_; 64 | int max_machine_; 65 | int stack_size_; 66 | int os_thread_stack_size_; 67 | bool ignore_sigpipe_; 68 | bool enable_stack_protection_; 69 | }; 70 | 71 | } // namespace tin 72 | -------------------------------------------------------------------------------- /tin/config/default.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | namespace tin { 8 | 9 | const int kDefaultStackSize = 64 * 1024; 10 | 11 | const int kStackAllignment = 64; 12 | 13 | const int kDefaultOSThreadStackSize = 640 * 1024; 14 | 15 | #define CACHELINE_SIZE 64; 16 | 17 | } // namespace tin 18 | 19 | -------------------------------------------------------------------------------- /tin/error/error_posix.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "tin/error/error.h" 12 | 13 | int TinTranslateSysError(int sys_errno) { 14 | if (sys_errno <= 0) { 15 | return sys_errno; /* If < 0 then it's already a libuv error. */ 16 | } 17 | return -sys_errno; 18 | } 19 | 20 | int TinGetaddrinfoTranslateError(int sys_errno) { 21 | if (sys_errno <= 0) { 22 | return sys_errno; /* If < 0 then it's already a libuv error. */ 23 | } 24 | return -sys_errno; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tin/io/io.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include "tin/error/error.h" 8 | #include "tin/runtime/runtime.h" 9 | #include "tin/io/io.h" 10 | 11 | 12 | namespace tin::io { 13 | 14 | int ReadAtLeast(Reader* reader, void* buf, int len, int min) { 15 | if (len < min) { 16 | SetErrorCode(TIN_EINVAL); 17 | return 0; 18 | } 19 | int err = 0; 20 | int n = 0; 21 | while (n < min && err == 0) { 22 | int nn = reader->Read(static_cast(buf) + n, len - n); 23 | DCHECK_GE(nn, 0); 24 | if (nn > 0) 25 | n += nn; 26 | err = GetErrorCode(); 27 | } 28 | if (n >= min) { 29 | SetErrorCode(0); 30 | } else if (n > 0 && err == TIN_EOF) { 31 | SetErrorCode(TIN_UNEXPECTED_EOF); 32 | } 33 | return n; 34 | } 35 | 36 | int ReadFull(Reader* reader, void* buf, int len) { 37 | return ReadAtLeast(reader, buf, len, len); 38 | } 39 | 40 | int Write(Writer* writer, void* buf, int len) { 41 | return writer->Write(buf, len); 42 | } 43 | 44 | int WriteString(Writer* writer, const absl::string_view& str) { 45 | return writer->Write(str.data(), static_cast(str.size())); 46 | } 47 | 48 | } // namespace tin::io 49 | 50 | -------------------------------------------------------------------------------- /tin/io/io.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include "tin/time/time.h" 7 | #include "absl/strings/string_view.h" 8 | 9 | namespace tin { 10 | namespace io { 11 | 12 | class Reader { 13 | public: 14 | virtual ~Reader() {} 15 | virtual int Read(void* buf, int nbytes) = 0; 16 | }; 17 | 18 | class Writer { 19 | public: 20 | virtual ~Writer() {} 21 | virtual int Write(const void* buf, int nbytes) = 0; 22 | }; 23 | 24 | class IOReadWriter : public Reader, public Writer { 25 | }; 26 | 27 | int ReadAtLeast(Reader* reader, void* buf, int nbytes, int min); 28 | 29 | int ReadFull(Reader* reader, void* buf, int nbytes); 30 | 31 | int Write(Writer* writer, const void* buf, int nbytes); 32 | 33 | int WriteString(Writer* writer, const absl::string_view& str); 34 | 35 | } // namespace io 36 | } // namespace tin 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tin/io/io_buffer.h: -------------------------------------------------------------------------------- 1 | // // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef PKG_IO_IO_BUFFER_H_ 6 | #define PKG_IO_IO_BUFFER_H_ 7 | 8 | #include 9 | 10 | 11 | namespace tin { 12 | 13 | class IOBuffer { 14 | public: 15 | 16 | public: 17 | IOBuffer(); 18 | explicit IOBuffer(size_t size); 19 | ~IOBuffer(); 20 | 21 | std::string str() const; 22 | 23 | typedef char* iterator; 24 | typedef const char* const_iterator; 25 | 26 | iterator begin() { return storage_ + read_idx_; } 27 | const_iterator begin() const { return storage_ + read_idx_; } 28 | 29 | iterator end() { return storage_ + write_idx_; } 30 | const_iterator end() const { return storage_ + write_idx_; } 31 | 32 | // The following functions all override pure virtual functions 33 | // in BufferInterface. See buffer_interface.h for a description 34 | // of what they do. 35 | int buffered() const { return write_idx_ - read_idx_; } 36 | int buffer_size() const { return storage_size_; } 37 | int free() const { return (storage_size_ - write_idx_); } 38 | bool empty() const { return (read_idx_ == write_idx_); } 39 | bool full() const { 40 | return ((write_idx_ == storage_size_) && (read_idx_ != write_idx_)); 41 | } 42 | 43 | // removes all data from the simple buffer 44 | void clear() { read_idx_ = write_idx_ = 0; } 45 | 46 | int Write(const void* ptr, size_t size); 47 | 48 | void GetWritablePtr(char** ptr, int* size) const; 49 | 50 | void GetReadablePtr(char** ptr, int* size) const; 51 | 52 | int Read(char* bytes, size_t size); 53 | 54 | void Reset(int size); 55 | 56 | // This can be an expensive operation: costing a new/delete, and copying of 57 | // all existing data. Even if the existing buffer does not need to be 58 | // resized, unread data may still need to be non-destructively copied to 59 | // consolidate fragmented free space. 60 | bool ReserveMore(int size); 61 | 62 | void AdvanceReadablePtr(int amount_to_advance); 63 | 64 | void AdvanceWritablePtr(int amount_to_advance); 65 | 66 | void Swap(IOBuffer* other); 67 | 68 | private: 69 | char* storage_; 70 | int write_idx_; 71 | int read_idx_; 72 | int storage_size_; 73 | 74 | public: 75 | IOBuffer(IOBuffer&& rvalue) { // NOLINT 76 | storage_ = rvalue.storage_; 77 | write_idx_ = rvalue.write_idx_; 78 | read_idx_ = rvalue.read_idx_; 79 | storage_size_ = rvalue.storage_size_; 80 | 81 | rvalue.storage_ = NULL; 82 | rvalue.write_idx_ = 0; 83 | rvalue.read_idx_ = 0; 84 | rvalue.storage_size_ = 0; 85 | } 86 | 87 | void operator=(IOBuffer&& rvalue) { 88 | delete storage_; 89 | storage_ = rvalue.storage_; 90 | write_idx_ = rvalue.write_idx_; 91 | read_idx_ = rvalue.read_idx_; 92 | storage_size_ = rvalue.storage_size_; 93 | 94 | rvalue.storage_ = NULL; 95 | rvalue.write_idx_ = 0; 96 | rvalue.read_idx_ = 0; 97 | rvalue.storage_size_ = 0; 98 | } 99 | }; 100 | 101 | } // namespace tin 102 | 103 | #endif // PKG_IO_IO_BUFFER_H_ 104 | -------------------------------------------------------------------------------- /tin/net/address_family.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "absl/log/log.h" 6 | #include "tin/net/address_family.h" 7 | #include "tin/net/ip_address.h" 8 | #include "tin/net/sys_addrinfo.h" 9 | 10 | namespace tin { 11 | namespace net { 12 | 13 | AddressFamily GetAddressFamily(const IPAddress& address) { 14 | if (address.IsIPv4()) { 15 | return ADDRESS_FAMILY_IPV4; 16 | } else if (address.IsIPv6()) { 17 | return ADDRESS_FAMILY_IPV6; 18 | } else { 19 | return ADDRESS_FAMILY_UNSPECIFIED; 20 | } 21 | } 22 | 23 | int ConvertAddressFamily(AddressFamily address_family) { 24 | switch (address_family) { 25 | case ADDRESS_FAMILY_UNSPECIFIED: 26 | return AF_UNSPEC; 27 | case ADDRESS_FAMILY_IPV4: 28 | return AF_INET; 29 | case ADDRESS_FAMILY_IPV6: 30 | return AF_INET6; 31 | } 32 | ABSL_ASSERT(false); 33 | return AF_UNSPEC; 34 | } 35 | 36 | } // namespace net 37 | } // namespace tin 38 | -------------------------------------------------------------------------------- /tin/net/address_family.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef NET_BASE_ADDRESS_FAMILY_H_ 6 | #define NET_BASE_ADDRESS_FAMILY_H_ 7 | 8 | 9 | namespace tin { 10 | namespace net { 11 | 12 | class IPAddress; 13 | 14 | // Enum wrapper around the address family types supported by host resolver 15 | // procedures. 16 | enum AddressFamily { 17 | ADDRESS_FAMILY_UNSPECIFIED, // AF_UNSPEC 18 | ADDRESS_FAMILY_IPV4, // AF_INET 19 | ADDRESS_FAMILY_IPV6, // AF_INET6 20 | ADDRESS_FAMILY_LAST = ADDRESS_FAMILY_IPV6 21 | }; 22 | 23 | // HostResolverFlags is a bitflag enum used by host resolver procedures to 24 | // determine the value of addrinfo.ai_flags and work around getaddrinfo 25 | // peculiarities. 26 | enum { 27 | HOST_RESOLVER_CANONNAME = 1 << 0, // AI_CANONNAME 28 | // Hint to the resolver proc that only loopback addresses are configured. 29 | HOST_RESOLVER_LOOPBACK_ONLY = 1 << 1, 30 | // Indicate the address family was set because no IPv6 support was detected. 31 | HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6 = 1 << 2, 32 | // The resolver should only invoke getaddrinfo, not DnsClient. 33 | HOST_RESOLVER_SYSTEM_ONLY = 1 << 3 34 | }; 35 | typedef int HostResolverFlags; 36 | 37 | // Returns AddressFamily for |address|. 38 | AddressFamily GetAddressFamily(const IPAddress& address); 39 | 40 | // Maps the given AddressFamily to either AF_INET, AF_INET6 or AF_UNSPEC. 41 | int ConvertAddressFamily(AddressFamily address_family); 42 | 43 | } // namespace net 44 | } // namespace tin 45 | 46 | #endif // NET_BASE_ADDRESS_FAMILY_H_ 47 | -------------------------------------------------------------------------------- /tin/net/address_list.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "tin/net/address_list.h" 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include "tin/net/sys_addrinfo.h" 12 | 13 | namespace tin { 14 | namespace net { 15 | 16 | 17 | AddressList::AddressList() {} 18 | 19 | AddressList::~AddressList() {} 20 | 21 | AddressList::AddressList(const IPEndPoint& endpoint) { 22 | push_back(endpoint); 23 | } 24 | 25 | // static 26 | AddressList AddressList::CreateFromIPAddress(const IPAddress& address, 27 | uint16_t port) { 28 | return AddressList(IPEndPoint(address, port)); 29 | } 30 | 31 | // static 32 | AddressList AddressList::CreateFromIPAddressList( 33 | const IPAddressList& addresses, 34 | const std::string& canonical_name) { 35 | AddressList list; 36 | list.set_canonical_name(canonical_name); 37 | for (IPAddressList::const_iterator iter = addresses.begin(); 38 | iter != addresses.end(); ++iter) { 39 | list.push_back(IPEndPoint(*iter, 0)); 40 | } 41 | return list; 42 | } 43 | 44 | // static 45 | AddressList AddressList::CreateFromAddrinfo(const struct addrinfo* head) { 46 | DCHECK(head); 47 | AddressList list; 48 | if (head->ai_canonname) 49 | list.set_canonical_name(std::string(head->ai_canonname)); 50 | for (const struct addrinfo* ai = head; ai; ai = ai->ai_next) { 51 | IPEndPoint ipe; 52 | // NOTE: Ignoring non-INET* families. 53 | if (ipe.FromSockAddr(ai->ai_addr, static_cast(ai->ai_addrlen))) 54 | list.push_back(ipe); 55 | else 56 | DLOG(WARNING) << "Unknown family found in addrinfo: " << ai->ai_family; 57 | } 58 | return list; 59 | } 60 | 61 | // static 62 | AddressList AddressList::CopyWithPort(const AddressList& list, uint16_t port) { 63 | AddressList out; 64 | out.set_canonical_name(list.canonical_name()); 65 | for (size_t i = 0; i < list.size(); ++i) 66 | out.push_back(IPEndPoint(list[i].address(), port)); 67 | return out; 68 | } 69 | 70 | void AddressList::SetDefaultCanonicalName() { 71 | DCHECK(!empty()); 72 | set_canonical_name(front().ToStringWithoutPort()); 73 | } 74 | 75 | } // namespace net 76 | } // namespace tin 77 | -------------------------------------------------------------------------------- /tin/net/address_list.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef NET_BASE_ADDRESS_LIST_H_ 6 | #define NET_BASE_ADDRESS_LIST_H_ 7 | 8 | 9 | #include 10 | #include 11 | 12 | #include "tin/net/ip_endpoint.h" 13 | 14 | 15 | struct addrinfo; 16 | 17 | namespace tin { 18 | namespace net { 19 | 20 | class IPAddress; 21 | 22 | class AddressList { 23 | public: 24 | AddressList(); 25 | AddressList(const AddressList&); 26 | ~AddressList(); 27 | 28 | // Creates an address list for a single IP literal. 29 | explicit AddressList(const IPEndPoint& endpoint); 30 | 31 | static AddressList CreateFromIPAddress(const IPAddress& address, 32 | uint16_t port); 33 | 34 | static AddressList CreateFromIPAddressList(const IPAddressList& addresses, 35 | const std::string& canonical_name); 36 | 37 | // Copies the data from |head| and the chained list into an AddressList. 38 | static AddressList CreateFromAddrinfo(const struct addrinfo* head); 39 | 40 | // Returns a copy of |list| with port on each element set to |port|. 41 | static AddressList CopyWithPort(const AddressList& list, uint16_t port); 42 | 43 | const std::string& canonical_name() const { 44 | return canonical_name_; 45 | } 46 | 47 | void set_canonical_name(const std::string& canonical_name) { 48 | canonical_name_ = canonical_name; 49 | } 50 | 51 | // Sets canonical name to the literal of the first IP address on the list. 52 | void SetDefaultCanonicalName(); 53 | 54 | // Creates a callback for use with the NetLog that returns a Value 55 | // representation of the address list. The callback must be destroyed before 56 | // |this| is. 57 | 58 | typedef std::vector::iterator iterator; 59 | typedef std::vector::const_iterator const_iterator; 60 | 61 | size_t size() const { 62 | return endpoints_.size(); 63 | } 64 | bool empty() const { 65 | return endpoints_.empty(); 66 | } 67 | void clear() { 68 | endpoints_.clear(); 69 | } 70 | void reserve(size_t count) { 71 | endpoints_.reserve(count); 72 | } 73 | size_t capacity() const { 74 | return endpoints_.capacity(); 75 | } 76 | IPEndPoint& operator[](size_t index) { 77 | return endpoints_[index]; 78 | } 79 | const IPEndPoint& operator[](size_t index) const { 80 | return endpoints_[index]; 81 | } 82 | IPEndPoint& front() { 83 | return endpoints_.front(); 84 | } 85 | const IPEndPoint& front() const { 86 | return endpoints_.front(); 87 | } 88 | IPEndPoint& back() { 89 | return endpoints_.back(); 90 | } 91 | const IPEndPoint& back() const { 92 | return endpoints_.back(); 93 | } 94 | void push_back(const IPEndPoint& val) { 95 | endpoints_.push_back(val); 96 | } 97 | 98 | template 99 | void insert(iterator pos, InputIt first, InputIt last) { 100 | endpoints_.insert(pos, first, last); 101 | } 102 | iterator begin() { 103 | return endpoints_.begin(); 104 | } 105 | const_iterator begin() const { 106 | return endpoints_.begin(); 107 | } 108 | iterator end() { 109 | return endpoints_.end(); 110 | } 111 | const_iterator end() const { 112 | return endpoints_.end(); 113 | } 114 | 115 | private: 116 | std::vector endpoints_; 117 | std::string canonical_name_; 118 | }; 119 | 120 | } // namespace net 121 | } // namespace tin 122 | 123 | #endif // NET_BASE_ADDRESS_LIST_H_ 124 | -------------------------------------------------------------------------------- /tin/net/dialer.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include "tin/error/error.h" 7 | #include "tin/time/time.h" 8 | #include "tin/net/ip_endpoint.h" 9 | #include "tin/net/netfd.h" 10 | #include "tin/net/dialer.h" 11 | #include "tin/runtime/runtime.h" 12 | 13 | namespace tin { 14 | namespace net { 15 | 16 | TcpConn DialTcpInternal(const IPAddress& address, uint16_t port, int64_t deadline) { 17 | int err = 0; 18 | AddressFamily family = 19 | address.IsIPv4() ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6; 20 | NetFD* netfd = NewFD(family, SOCK_STREAM, &err); 21 | if (netfd != NULL) { 22 | IPEndPoint endpoint(address, port); 23 | if (deadline == -1) 24 | deadline = UINT64_MAX; 25 | err = netfd->Dial(NULL, &endpoint, UINT64_MAX); 26 | if (err != 0) { 27 | delete netfd; 28 | netfd = NULL; 29 | } 30 | } 31 | SetErrorCode(TinTranslateSysError(err)); 32 | return MakeTcpConn(new TcpConnImpl(netfd)); 33 | } 34 | 35 | TcpConn DialTcpInternal(const absl::string_view& address, uint16_t port, 36 | int64_t deadline) { 37 | IPAddress ip_address; 38 | if (!ip_address.AssignFromIPLiteral(address)) { 39 | SetErrorCode(TIN_EINVAL); 40 | return TcpConn(NULL); 41 | } 42 | return DialTcpInternal(ip_address, port, deadline); 43 | } 44 | 45 | TcpConn DialTcp(const IPAddress& address, uint16_t port) { 46 | return DialTcpInternal(address, port, -1); 47 | } 48 | 49 | TcpConn DialTcp(const absl::string_view& address, uint16_t port) { 50 | return DialTcpInternal(address, port, -1); 51 | } 52 | 53 | TcpConn DialTcpTimeout(const IPAddress& address, uint16_t port, int64_t deadline) { 54 | return DialTcpInternal(address, port, deadline); 55 | } 56 | 57 | TcpConn DialTcpTimeout(const absl::string_view& address, uint16_t port, 58 | int64_t deadline) { 59 | return DialTcpInternal(address, port, deadline); 60 | } 61 | 62 | TCPListener ListenTcp(const IPAddress& address, uint16_t port, int backlog) { 63 | int err = 0; 64 | AddressFamily family = 65 | address.IsIPv4() ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6; 66 | NetFD* netfd = NewFD(family, SOCK_STREAM, &err); 67 | if (netfd != NULL) { 68 | err = netfd->Init(); 69 | if (err == 0) { 70 | #if defined(OS_POSIX) 71 | int on = 1; 72 | err = netfd->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 73 | #endif 74 | } 75 | if (err == 0) { 76 | IPEndPoint endpoint(address, port); 77 | err = netfd->Bind(endpoint); 78 | if(err != 0) { 79 | LOG(INFO) << "Bind failed: " << tin::GetErrorStr(); 80 | } 81 | } 82 | } 83 | if (err == 0) { 84 | err = netfd->Listen(backlog); 85 | } 86 | if (err != 0 && netfd != NULL) { 87 | delete netfd; 88 | netfd = NULL; 89 | } 90 | TCPListenerImpl* listener = NULL; 91 | if (netfd != NULL) { 92 | listener = new TCPListenerImpl(netfd, backlog); 93 | } 94 | SetErrorCode(TinTranslateSysError(err)); 95 | return TCPListener(listener); 96 | } 97 | 98 | TCPListener ListenTcp(const absl::string_view& address, uint16_t port, 99 | int backlog) { 100 | IPAddress ip_address; 101 | if (!ip_address.AssignFromIPLiteral(address)) { 102 | SetErrorCode(TIN_EINVAL); 103 | return TCPListener(NULL); 104 | } 105 | return ListenTcp(ip_address, port, backlog); 106 | } 107 | 108 | } // namespace net 109 | } // namespace tin 110 | -------------------------------------------------------------------------------- /tin/net/dialer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | 8 | #include 9 | #include "tin/net/ip_address.h" 10 | #include "tin/net/tcp_conn.h" 11 | #include "tin/net/listener.h" 12 | 13 | namespace tin { 14 | namespace net { 15 | 16 | TcpConn DialTcp(const IPAddress& address, uint16_t port); 17 | 18 | TcpConn DialTcp(const absl::string_view& addr, uint16_t port); 19 | 20 | TcpConn DialTcpTimeout(const IPAddress& address, uint16_t port, int64_t deadline); 21 | 22 | TcpConn DialTcpTimeout(const absl::string_view& addr, uint16_t port, 23 | int64_t deadline); 24 | 25 | TCPListener ListenTcp(const absl::string_view& addr, uint16_t port, 26 | int backlog = 511); 27 | 28 | } // namespace net 29 | } // namespace tin 30 | 31 | -------------------------------------------------------------------------------- /tin/net/fd_mutex.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | 8 | #include "tin/net/fd_mutex.h" 9 | #include "tin/runtime/runtime.h" 10 | 11 | namespace tin { 12 | 13 | void RuntimeSemacquire(uint32_t* addr); 14 | void RuntimeSemrelease(uint32_t* addr); 15 | 16 | namespace net { 17 | 18 | const uint64_t kMutexClosed = (uint64_t)1LL << 0; // NOLINT 19 | const uint64_t kMutexRLock = (uint64_t)1LL << 1; // NOLINT 20 | const uint64_t kMutexWLock = (uint64_t)1LL << 2; // NOLINT 21 | const uint64_t kMutexRef = (uint64_t)1LL << 3; // NOLINT 22 | const uint64_t kMutexRefMask = (uint64_t)((1LL << 20) - 1) << 3; // NOLINT 23 | const uint64_t kMutexRWait = (uint64_t)1LL << 23; // NOLINT 24 | const uint64_t kMutexRMask = (uint64_t)((1LL << 20) - 1) << 23; // NOLINT 25 | const uint64_t kMutexWWait = (uint64_t)1LL << 43; // NOLINT 26 | const uint64_t kMutexWMask = (uint64_t)((1LL << 20) - 1) << 43; // NOLINT 27 | 28 | bool FdMutex::Incref() { 29 | while (true) { 30 | uint64_t old_value = state_.load(quark::memory_order_acquire); 31 | if ((old_value & kMutexClosed) != 0) { 32 | // already closed, return false. 33 | return false; 34 | } 35 | uint64_t new_value = old_value + kMutexRef; 36 | if ((new_value & kMutexRefMask) == 0) { 37 | LOG(FATAL) << "net: inconsistent fdMutex"; 38 | } 39 | 40 | if (state_.compare_exchange_strong(old_value, new_value)) { 41 | return true; 42 | } 43 | } 44 | } 45 | 46 | bool FdMutex::IncrefAndClose() { 47 | while (true) { 48 | uint64_t old_value = state_.load(quark::memory_order_acquire); 49 | if ((old_value & kMutexClosed) != 0) { 50 | return false; 51 | } 52 | // Mark as closed and acquire a reference. 53 | uint64_t new_value = (old_value | kMutexClosed) + kMutexRef; 54 | if ((new_value & kMutexRefMask) == 0) { 55 | LOG(FATAL) << "net: inconsistent fdMutex"; 56 | } 57 | 58 | // Remove all read and write waiters. 59 | new_value &= ~(kMutexRMask | kMutexWMask); 60 | if (state_.compare_exchange_strong(old_value, new_value)) { 61 | while ((old_value & kMutexRMask) != 0) { 62 | old_value -= kMutexRWait; 63 | RuntimeSemrelease(&rsema_); 64 | } 65 | while ((old_value & kMutexWMask) != 0) { 66 | old_value -= kMutexWWait; 67 | RuntimeSemrelease(&wsema_); 68 | } 69 | return true; 70 | } 71 | } 72 | } 73 | 74 | bool FdMutex::Deref() { 75 | while (true) { 76 | uint64_t old_value = state_.load(quark::memory_order_acquire); 77 | if ((old_value & kMutexRefMask) == 0) { 78 | LOG(FATAL) << "net: inconsistent fdMutex"; 79 | } 80 | uint64_t new_value = old_value - kMutexRef; 81 | if (state_.compare_exchange_strong(old_value, new_value)) { 82 | return (new_value & (kMutexClosed | kMutexRefMask)) == kMutexClosed; 83 | } 84 | } 85 | } 86 | 87 | bool FdMutex::RWLock(bool read) { 88 | uint64_t mutex_bit, mutex_wait, mutex_mask; 89 | uint32_t* mutex_sema; 90 | if (read) { 91 | mutex_bit = kMutexRLock; 92 | mutex_wait = kMutexRWait; 93 | mutex_mask = kMutexRMask; 94 | mutex_sema = &rsema_; 95 | } else { 96 | mutex_bit = kMutexWLock; 97 | mutex_wait = kMutexWWait; 98 | mutex_mask = kMutexWMask; 99 | mutex_sema = &wsema_; 100 | } 101 | 102 | while (true) { 103 | uint64_t old_value = state_.load(quark::memory_order_acquire); 104 | if ((old_value & kMutexClosed) != 0) { 105 | return false; 106 | } 107 | uint64_t new_value; 108 | if ((old_value & mutex_bit) == 0) { 109 | // Lock is free, acquire it. 110 | new_value = (old_value | mutex_bit) + kMutexRef; 111 | if ((new_value & kMutexRefMask) == 0) { 112 | LOG(FATAL) << "net: inconsistent fdMutex"; 113 | } 114 | } else { 115 | // Wait for lock. 116 | new_value = old_value + mutex_wait; 117 | if ((new_value & mutex_mask) == 0) { 118 | LOG(FATAL) << "net: inconsistent fdMutex"; 119 | } 120 | } 121 | if (state_.compare_exchange_strong(old_value, new_value)) { 122 | if ((old_value & mutex_bit) == 0) { 123 | return true; 124 | } 125 | RuntimeSemacquire(mutex_sema); 126 | } 127 | } 128 | } 129 | 130 | bool FdMutex::RWUnlock(bool read) { 131 | uint64_t mutex_bit, mutex_wait, mutex_mask; 132 | uint32_t* mutex_sema; 133 | if (read) { 134 | mutex_bit = kMutexRLock; 135 | mutex_wait = kMutexRWait; 136 | mutex_mask = kMutexRMask; 137 | mutex_sema = &rsema_; 138 | } else { 139 | mutex_bit = kMutexWLock; 140 | mutex_wait = kMutexWWait; 141 | mutex_mask = kMutexWMask; 142 | mutex_sema = &wsema_; 143 | } 144 | 145 | while (true) { 146 | uint64_t old_value = state_.load(quark::memory_order_acquire); 147 | if (((old_value & mutex_bit) == 0) || ((old_value & kMutexRefMask) == 0)) { 148 | LOG(FATAL) << "net: inconsistent fdMutex"; 149 | } 150 | // Drop lock, drop reference and wake read waiter if present. 151 | uint64_t new_value = (old_value & ~mutex_bit) - kMutexRef; 152 | if ((old_value & mutex_mask) != 0) { 153 | new_value -= mutex_wait; 154 | } 155 | 156 | if (state_.compare_exchange_strong(old_value, new_value)) { 157 | if ((old_value & mutex_mask) != 0) { 158 | RuntimeSemrelease(mutex_sema); 159 | return true; 160 | } 161 | return (new_value & (kMutexClosed | kMutexRefMask)) == kMutexClosed; 162 | } 163 | } 164 | } 165 | 166 | } // namespace net 167 | } // namespace tin 168 | -------------------------------------------------------------------------------- /tin/net/fd_mutex.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include "cstdint" 7 | #include "quark/atomic.hpp" 8 | 9 | namespace tin { 10 | namespace net { 11 | 12 | class FdMutex { 13 | public: 14 | FdMutex() 15 | : state_(0) 16 | , rsema_(0) 17 | , wsema_(0) 18 | {}; 19 | bool Incref(); 20 | bool IncrefAndClose(); 21 | bool Deref(); 22 | bool RWLock(bool read); 23 | bool RWUnlock(bool read); 24 | 25 | private: 26 | quark::atomic_uint64_t state_; 27 | uint32_t rsema_; 28 | uint32_t wsema_; 29 | }; 30 | 31 | } // namespace net 32 | } // namespace tin 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /tin/net/inet.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | 8 | namespace tin { 9 | namespace net { 10 | 11 | int InetNToP(int af, const void* src, char* dst, size_t size); 12 | 13 | int INetPToN(int af, const char* src, void* dst); 14 | 15 | // c++ version. 16 | bool InetNToP(bool ipv4, const void* src, std::string* dst); 17 | 18 | bool INetPToN(bool ipv4, const char* src, void* dst); 19 | 20 | } // namespace net 21 | } // namespace tin 22 | -------------------------------------------------------------------------------- /tin/net/ip_endpoint.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | 6 | 7 | #include 8 | 9 | #if defined(OS_WIN) 10 | #include 11 | #include 12 | #elif defined(OS_POSIX) 13 | #include 14 | #endif 15 | 16 | #include 17 | #include 18 | 19 | #include "tin/net/ip_address.h" 20 | 21 | #if defined(OS_WIN) 22 | #include "tin/net/winsock_util.h" 23 | #endif 24 | 25 | #include "tin/net/ip_endpoint.h" 26 | 27 | namespace tin { 28 | namespace net { 29 | 30 | namespace { 31 | 32 | // By definition, socklen_t is large enough to hold both sizes. 33 | const socklen_t kSockaddrInSize = sizeof(struct sockaddr_in); 34 | const socklen_t kSockaddrIn6Size = sizeof(struct sockaddr_in6); 35 | 36 | // Extracts the address and port portions of a sockaddr. 37 | bool GetIPAddressFromSockAddr(const struct sockaddr* sock_addr, 38 | socklen_t sock_addr_len, 39 | const uint8_t** address, 40 | size_t* address_len, 41 | uint16_t* port) { 42 | if (sock_addr->sa_family == AF_INET) { 43 | if (sock_addr_len < static_cast(sizeof(struct sockaddr_in))) 44 | return false; 45 | const struct sockaddr_in* addr = 46 | reinterpret_cast(sock_addr); 47 | *address = reinterpret_cast(&addr->sin_addr); 48 | *address_len = IPAddress::kIPv4AddressSize; 49 | if (port) 50 | *port = cliff::NetToHost16(addr->sin_port); 51 | return true; 52 | } 53 | 54 | if (sock_addr->sa_family == AF_INET6) { 55 | if (sock_addr_len < static_cast(sizeof(struct sockaddr_in6))) 56 | return false; 57 | const struct sockaddr_in6* addr = 58 | reinterpret_cast(sock_addr); 59 | *address = reinterpret_cast(&addr->sin6_addr); 60 | *address_len = IPAddress::kIPv6AddressSize; 61 | if (port) 62 | *port = cliff::NetToHost16(addr->sin6_port); 63 | return true; 64 | } 65 | 66 | #if defined(OS_WIN) 67 | if (sock_addr->sa_family == AF_BTH) { 68 | if (sock_addr_len < static_cast(sizeof(SOCKADDR_BTH))) 69 | return false; 70 | const SOCKADDR_BTH* addr = reinterpret_cast(sock_addr); 71 | *address = reinterpret_cast(&addr->btAddr); 72 | *address_len = kBluetoothAddressSize; 73 | if (port) 74 | *port = static_cast(addr->port); 75 | return true; 76 | } 77 | #endif 78 | 79 | return false; // Unrecognized |sa_family|. 80 | } 81 | 82 | } // namespace 83 | 84 | IPEndPoint::IPEndPoint() : port_(0) {} 85 | 86 | IPEndPoint::~IPEndPoint() {} 87 | 88 | IPEndPoint::IPEndPoint(const IPAddress& address, uint16_t port) 89 | : address_(address), port_(port) {} 90 | 91 | IPEndPoint::IPEndPoint(const IPEndPoint& endpoint) { 92 | address_ = endpoint.address_; 93 | port_ = endpoint.port_; 94 | } 95 | 96 | AddressFamily IPEndPoint::GetFamily() const { 97 | return GetAddressFamily(address_); 98 | } 99 | 100 | int IPEndPoint::GetSockAddrFamily() const { 101 | switch (address_.size()) { 102 | case IPAddress::kIPv4AddressSize: 103 | return AF_INET; 104 | case IPAddress::kIPv6AddressSize: 105 | return AF_INET6; 106 | default: 107 | // NOTREACHED() << "Bad IP address"; 108 | 109 | return AF_UNSPEC; 110 | } 111 | } 112 | 113 | bool IPEndPoint::ToSockAddr(struct sockaddr* address, 114 | socklen_t* address_length) const { 115 | DCHECK(address); 116 | DCHECK(address_length); 117 | switch (address_.size()) { 118 | case IPAddress::kIPv4AddressSize: { 119 | if (*address_length < kSockaddrInSize) 120 | return false; 121 | *address_length = kSockaddrInSize; 122 | struct sockaddr_in* addr = reinterpret_cast(address); 123 | memset(addr, 0, sizeof(struct sockaddr_in)); 124 | addr->sin_family = AF_INET; 125 | addr->sin_port = cliff::HostToNet16(port_); 126 | memcpy(&addr->sin_addr, &address_.bytes()[0], // vector_as_array 127 | IPAddress::kIPv4AddressSize); 128 | break; 129 | } 130 | case IPAddress::kIPv6AddressSize: { 131 | if (*address_length < kSockaddrIn6Size) 132 | return false; 133 | *address_length = kSockaddrIn6Size; 134 | struct sockaddr_in6* addr6 = 135 | reinterpret_cast(address); 136 | memset(addr6, 0, sizeof(struct sockaddr_in6)); 137 | addr6->sin6_family = AF_INET6; 138 | addr6->sin6_port = cliff::HostToNet16(port_); 139 | memcpy(&addr6->sin6_addr, &address_.bytes()[0], // vector_as_array(&address_.bytes()), 140 | IPAddress::kIPv6AddressSize); 141 | break; 142 | } 143 | default: 144 | return false; 145 | } 146 | return true; 147 | } 148 | 149 | bool IPEndPoint::FromSockAddr(const struct sockaddr* sock_addr, 150 | socklen_t sock_addr_len) { 151 | DCHECK(sock_addr); 152 | 153 | const uint8_t* address; 154 | size_t address_len; 155 | uint16_t port; 156 | if (!GetIPAddressFromSockAddr(sock_addr, sock_addr_len, &address, 157 | &address_len, &port)) { 158 | return false; 159 | } 160 | 161 | address_ = net::IPAddress(address, address_len); 162 | port_ = port; 163 | return true; 164 | } 165 | 166 | std::string IPEndPoint::ToString() const { 167 | return IPAddressToStringWithPort(address_, port_); 168 | } 169 | 170 | std::string IPEndPoint::ToStringWithoutPort() const { 171 | return address_.ToString(); 172 | } 173 | 174 | bool IPEndPoint::operator<(const IPEndPoint& other) const { 175 | // Sort IPv4 before IPv6. 176 | if (address_.size() != other.address_.size()) { 177 | return address_.size() < other.address_.size(); 178 | } 179 | if (address_ != other.address_) { 180 | return address_ < other.address_; 181 | } 182 | return port_ < other.port_; 183 | } 184 | 185 | bool IPEndPoint::operator==(const IPEndPoint& other) const { 186 | return address_ == other.address_ && port_ == other.port_; 187 | } 188 | 189 | } // namespace net 190 | } // namespace tin 191 | -------------------------------------------------------------------------------- /tin/net/ip_endpoint.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef NET_BASE_IP_ENDPOINT_H_ 6 | #define NET_BASE_IP_ENDPOINT_H_ 7 | 8 | #include 9 | 10 | #include "tin/net/address_family.h" 11 | #include "tin/net/ip_address.h" 12 | #include "tin/net/sys_addrinfo.h" 13 | 14 | struct sockaddr; 15 | 16 | namespace tin { 17 | namespace net { 18 | 19 | // An IPEndPoint represents the address of a transport endpoint: 20 | // * IP address (either v4 or v6) 21 | // * Port 22 | class IPEndPoint { 23 | public: 24 | IPEndPoint(); 25 | ~IPEndPoint(); 26 | IPEndPoint(const IPAddress& address, uint16_t port); 27 | IPEndPoint(const IPEndPoint& endpoint); 28 | 29 | const IPAddress& address() const { 30 | return address_; 31 | } 32 | uint16_t port() const { 33 | return port_; 34 | } 35 | 36 | // Returns AddressFamily of the address. 37 | AddressFamily GetFamily() const; 38 | 39 | // Returns the sockaddr family of the address, AF_INET or AF_INET6. 40 | int GetSockAddrFamily() const; 41 | 42 | // Convert to a provided sockaddr struct. 43 | // |address| is the sockaddr to copy into. Should be at least 44 | // sizeof(struct sockaddr_storage) bytes. 45 | // |address_length| is an input/output parameter. On input, it is the 46 | // size of data in |address| available. On output, it is the size of 47 | // the address that was copied into |address|. 48 | // Returns true on success, false on failure. 49 | bool ToSockAddr(struct sockaddr* address, socklen_t* address_length) const 50 | ABSL_MUST_USE_RESULT; 51 | 52 | // Convert from a sockaddr struct. 53 | // |address| is the address. 54 | // |address_length| is the length of |address|. 55 | // Returns true on success, false on failure. 56 | bool FromSockAddr(const struct sockaddr* address, socklen_t address_length) 57 | ABSL_MUST_USE_RESULT; 58 | 59 | // Returns value as a string (e.g. "127.0.0.1:80"). Returns the empty string 60 | // when |address_| is invalid (the port will be ignored). 61 | std::string ToString() const; 62 | 63 | // As above, but without port. Returns the empty string when address_ is 64 | // invalid. 65 | std::string ToStringWithoutPort() const; 66 | 67 | bool operator<(const IPEndPoint& that) const; 68 | bool operator==(const IPEndPoint& that) const; 69 | 70 | private: 71 | IPAddress address_; 72 | uint16_t port_; 73 | }; 74 | 75 | } // namespace net 76 | } // namespace tin 77 | 78 | #endif // NET_BASE_IP_ENDPOINT_H_ 79 | -------------------------------------------------------------------------------- /tin/net/listener.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "build/build_config.h" 6 | 7 | #include "tin/net/sys_socket.h" 8 | #include "tin/error/error.h" 9 | #include "tin/time/time.h" 10 | #include "tin/runtime/runtime.h" 11 | #include "tin/net/netfd.h" 12 | 13 | #include "tin/net/listener.h" 14 | 15 | namespace tin { 16 | namespace net { 17 | 18 | TCPListenerImpl::TCPListenerImpl(NetFD* netfd, int backlog) 19 | : netfd_(netfd) { 20 | } 21 | 22 | TCPListenerImpl::~TCPListenerImpl() { 23 | delete netfd_; 24 | } 25 | 26 | void TCPListenerImpl::SetDeadline(int64_t t) { 27 | int err = netfd_->SetDeadline(t); 28 | SetErrorCode(TinTranslateSysError(err)); 29 | } 30 | 31 | void TCPListenerImpl::Close() { 32 | int err = netfd_->Close(); 33 | SetErrorCode(TinTranslateSysError(err)); 34 | } 35 | 36 | TcpConn TCPListenerImpl::Accept() { 37 | NetFD* newfd = NULL; 38 | TcpConnImpl* conn = NULL; 39 | int err = netfd_->Accept(&newfd); 40 | if (err == 0) { 41 | conn = new TcpConnImpl(newfd); 42 | } 43 | SetErrorCode(TinTranslateSysError(err)); 44 | return MakeTcpConn(conn); 45 | } 46 | 47 | } // namespace net 48 | } // namespace tin 49 | -------------------------------------------------------------------------------- /tin/net/listener.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | 8 | #include "tin/time/time.h" 9 | #include "tin/net/tcp_conn.h" 10 | 11 | namespace tin::net { 12 | 13 | class NetFD; 14 | 15 | class TCPListenerImpl 16 | : public std::enable_shared_from_this { 17 | public: 18 | TCPListenerImpl(NetFD* netfd, int backlog); 19 | ~TCPListenerImpl(); 20 | 21 | TCPListenerImpl(const TCPListenerImpl&) = delete; 22 | TCPListenerImpl& operator=(const TCPListenerImpl&) = delete; 23 | 24 | void SetDeadline(int64_t t); 25 | TcpConn Accept(); 26 | void Close(); 27 | 28 | private: 29 | NetFD* netfd_; 30 | }; 31 | 32 | 33 | class TCPListener { 34 | public: 35 | explicit TCPListener(TCPListenerImpl* conn) 36 | : impl_(conn) { 37 | } 38 | TCPListener(const TCPListener& other) = default; 39 | 40 | TCPListenerImpl* operator->() { 41 | return impl_.get(); 42 | } 43 | 44 | private: 45 | std::shared_ptr impl_; 46 | }; 47 | 48 | inline TCPListener MakeTcpListener(TCPListenerImpl* listener) { 49 | return TCPListener(listener); 50 | } 51 | 52 | } // namespace tin::net 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /tin/net/net.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "tin/net/net.h" 6 | 7 | namespace tin { 8 | 9 | namespace net { 10 | 11 | } // namespace net 12 | } // namespace tin 13 | -------------------------------------------------------------------------------- /tin/net/net.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include "tin/time/time.h" 7 | 8 | namespace tin { 9 | namespace net { 10 | 11 | } // namespace net 12 | } // namespace tin 13 | 14 | -------------------------------------------------------------------------------- /tin/net/netfd.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include "build/build_config.h" 8 | 9 | #ifdef OS_WIN 10 | #include "tin/net/netfd_windows.h" 11 | #else 12 | #include "tin/net/netfd_posix.h" 13 | #endif 14 | 15 | namespace tin { 16 | namespace net { 17 | 18 | } // namespace net 19 | } // namespace tin 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tin/net/netfd_common.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "tin/net/sys_socket.h" 6 | #include "tin/error/error.h" 7 | #include "tin/runtime/runtime.h" 8 | #include "tin/runtime/net/pollops.h" 9 | #include "tin/net/net.h" 10 | #include "tin/net/sockaddr_storage.h" 11 | #include "tin/net/ip_address.h" 12 | 13 | #include "tin/net/netfd_common.h" 14 | 15 | namespace tin { 16 | namespace net { 17 | 18 | NetFDCommon::NetFDCommon(uintptr_t sysfd, 19 | AddressFamily family, 20 | int sotype, 21 | const std::string& net) 22 | : sysfd_(sysfd) 23 | , family_(family) 24 | , sotype_(sotype) 25 | , net_(net) { 26 | } 27 | 28 | NetFDCommon::~NetFDCommon() { 29 | // note: do never ever call Destroy here(destructor), it is implemented in 30 | // sub-class NetFD as virtual. 31 | } 32 | 33 | int NetFDCommon::Close() { 34 | if (!fdmu_.IncrefAndClose()) { 35 | return TIN_ECLOSE_INTR; 36 | } 37 | // unblock pending reader and writer 38 | pd_.Evict(); 39 | Decref(); 40 | return 0; 41 | } 42 | 43 | int NetFDCommon::Incref() { 44 | if (!fdmu_.Incref()) { 45 | return TIN_ECLOSE_INTR; 46 | } 47 | return 0; 48 | } 49 | 50 | void NetFDCommon::Decref() { 51 | if (fdmu_.Deref()) { 52 | Destroy(); 53 | } 54 | } 55 | 56 | int NetFDCommon::ReadLock() { 57 | if (!fdmu_.RWLock(true)) { 58 | return TIN_ECLOSE_INTR; 59 | } 60 | return 0; 61 | } 62 | 63 | void NetFDCommon::ReadUnlock() { 64 | if (fdmu_.RWUnlock(true)) { 65 | Destroy(); 66 | } 67 | } 68 | 69 | int NetFDCommon::WriteLock() { 70 | if (!fdmu_.RWLock(false)) { 71 | return TIN_ECLOSE_INTR; 72 | } 73 | return 0; 74 | } 75 | 76 | void NetFDCommon::WriteUnlock() { 77 | if (fdmu_.RWUnlock(false)) { 78 | Destroy(); 79 | } 80 | } 81 | 82 | int NetFDCommon::SetDeadline(int64_t t) { 83 | return SetDeadlineImpl(t, 'r' + 'w'); 84 | } 85 | 86 | int NetFDCommon::SetReadDeadline(int64_t t) { 87 | return SetDeadlineImpl(t, 'r'); 88 | } 89 | 90 | int NetFDCommon::SetWriteDeadline(int64_t t) { 91 | return SetDeadlineImpl(t, 'w'); 92 | } 93 | 94 | int NetFDCommon::SetDeadlineImpl(int64_t t, int mode) { 95 | int64_t now = MonoNow(); 96 | int64_t d = now + t; 97 | // test overflow. 98 | if (std::numeric_limits::max() - now < t) { 99 | d = std::numeric_limits::max(); 100 | } 101 | if (t == 0) { 102 | d = 0; 103 | } 104 | int err = Incref(); 105 | if (err != 0) 106 | return err; 107 | tin::runtime::pollops::SetDeadline(pd_.Desc(), d, mode); 108 | Decref(); 109 | return 0; 110 | } 111 | 112 | } // namespace net 113 | } // namespace tin 114 | -------------------------------------------------------------------------------- /tin/net/netfd_common.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include "tin/net/fd_mutex.h" 8 | #include "tin/net/poll_desc.h" 9 | #include "tin/net/address_list.h" 10 | #include "tin/net/ip_endpoint.h" 11 | #include "tin/net/sockaddr_storage.h" 12 | 13 | 14 | namespace tin::net { 15 | 16 | const uintptr_t kInvalidSocket = uintptr_t(~0); 17 | 18 | class NetFDCommon { 19 | public: 20 | NetFDCommon(uintptr_t sysfd, 21 | AddressFamily family, 22 | int sotype, 23 | const std::string& net); 24 | 25 | NetFDCommon(const NetFDCommon&) = delete; 26 | NetFDCommon& operator=(const NetFDCommon&) = delete; 27 | 28 | virtual ~NetFDCommon(); 29 | 30 | int Incref(); 31 | 32 | int ReadLock(); 33 | 34 | void ReadUnlock(); 35 | 36 | int WriteLock(); 37 | 38 | void WriteUnlock(); 39 | 40 | virtual void Destroy() = 0; 41 | 42 | int Close(); 43 | 44 | int SetDeadline(int64_t t); 45 | 46 | int SetReadDeadline(int64_t t); 47 | 48 | int SetWriteDeadline(int64_t t); 49 | 50 | int SetDeadlineImpl(int64_t t, int mode); 51 | 52 | void Decref(); 53 | 54 | PollDesc* Pd() { 55 | return &pd_; 56 | } 57 | 58 | uintptr_t SysFd() { 59 | return sysfd_; 60 | } 61 | 62 | int IntFd() const { 63 | return static_cast(sysfd_); 64 | } 65 | 66 | protected: 67 | FdMutex fdmu_; 68 | uintptr_t sysfd_; 69 | AddressFamily family_; 70 | int sotype_; 71 | int is_connected_; 72 | std::string net_; 73 | PollDesc pd_; 74 | }; 75 | } // namespace tin::net 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /tin/net/netfd_posix.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include "tin/net/fd_mutex.h" 8 | #include "tin/net/poll_desc.h" 9 | #include "tin/net/address_list.h" 10 | #include "tin/net/ip_endpoint.h" 11 | #include "tin/net/sockaddr_storage.h" 12 | #include "tin/net/netfd_common.h" 13 | 14 | namespace tin { 15 | namespace net { 16 | 17 | class NetFD : public NetFDCommon { 18 | public: 19 | NetFD(uintptr_t sysfd, 20 | AddressFamily family, 21 | int sotype, 22 | const std::string& net); 23 | 24 | virtual ~NetFD(); 25 | 26 | int Init(); 27 | 28 | int Read(void* buf, int len, int* nread); 29 | 30 | int Write(const void* buf, int len, int* nwritten); 31 | 32 | virtual void Destroy(); 33 | 34 | int Shutdown(int how); 35 | 36 | int CloseRead(); 37 | 38 | int CloseWrite(); 39 | 40 | int Dial(IPEndPoint* local, IPEndPoint* remote, int64_t deadline); 41 | 42 | int Bind(const IPEndPoint& address); 43 | 44 | int Listen(int backlog = 511); 45 | 46 | int Accept(NetFD** newfd); 47 | 48 | int EofError(int n, int err); 49 | 50 | int GetSockOpt(int level, int name, void* optval, 51 | socklen_t* optlen); 52 | 53 | int SetSockOpt(int level, int name, const void* optval, 54 | socklen_t); 55 | 56 | int SetTCPKeepAlive(bool enable, int sec); 57 | 58 | private: 59 | int Connect(SockaddrStorage* laddr, SockaddrStorage* raddr, int64_t deadline); 60 | int AcceptImpl(NetFD** newfd); 61 | }; 62 | 63 | NetFD* NewFD(AddressFamily family, int sotype, int* error_code = NULL); 64 | 65 | } // namespace net 66 | } // namespace tin 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /tin/net/netfd_windows.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include "tin/platform/platform_win.h" 12 | #include "tin/net/fd_mutex.h" 13 | #include "tin/net/poll_desc.h" 14 | #include "tin/net/address_list.h" 15 | #include "tin/net/ip_endpoint.h" 16 | #include "tin/communication/chan.h" 17 | 18 | #include "tin/net/netfd_common.h" 19 | 20 | namespace tin { 21 | namespace net { 22 | 23 | class NetFD; 24 | struct SockaddrStorage; 25 | 26 | struct Operation { 27 | Operation() 28 | : sa(NULL) 29 | , rsan(0) 30 | , accept_buf() 31 | , handle(NULL) 32 | , error_no(0) 33 | , qty(0) 34 | , flags(0) 35 | , fd(NULL) 36 | , mode(0) 37 | , err_chan(tin::MakeChan(1)) { 38 | } 39 | 40 | ~Operation() { 41 | } 42 | 43 | void InitBuf(void* ptr, int len) { 44 | buf.buf = static_cast(ptr); 45 | buf.len = len; 46 | } 47 | 48 | int io_type; 49 | OVERLAPPED overlapped; 50 | uintptr_t runtime_ctx; 51 | int32_t mode; 52 | int32_t error_no; 53 | DWORD qty; 54 | 55 | NetFD* fd; 56 | WSABUF buf; 57 | SockaddrStorage* sa; 58 | DWORD flags; 59 | uintptr_t handle; // listen socket handle. 60 | std::unique_ptr accept_buf; 61 | int32_t rsan; 62 | tin::Chan err_chan; 63 | }; 64 | 65 | class NetFD : public NetFDCommon { 66 | public: 67 | NetFD(uintptr_t sysfd, 68 | AddressFamily family, 69 | int sotype, 70 | const std::string& net); 71 | 72 | virtual ~NetFD(); 73 | 74 | int Init(); 75 | 76 | int Read(void* buf, int len, int* nread); 77 | 78 | int Write(const void* buf, int len, int* nwritten); 79 | 80 | virtual void Destroy(); 81 | 82 | int Shutdown(int how); 83 | 84 | int CloseRead(); 85 | 86 | int CloseWrite(); 87 | 88 | int Dial(IPEndPoint* local, IPEndPoint* remote, int64_t deadline); 89 | 90 | int Bind(const IPEndPoint& address); 91 | 92 | int Listen(int backlog = 511); 93 | 94 | int Accept(NetFD** newfd); 95 | 96 | int EofError(int n, int err); 97 | 98 | int GetSockOpt(int level, int name, void* optval, socklen_t* optlen); 99 | 100 | int SetSockOpt(int level, int name, const void* optval, socklen_t optlen); 101 | 102 | int SetTCPKeepAlive(bool enable, int sec); 103 | 104 | bool SkipSyncNotification() { 105 | return skip_sync_notification_; 106 | } 107 | 108 | private: 109 | int Connect(SockaddrStorage* laddr, SockaddrStorage* raddr, int64_t deadline); 110 | int AcceptOne(Operation* op, NetFD** newfd); 111 | 112 | private: 113 | bool skip_sync_notification_; 114 | Operation rop_; 115 | Operation wop_; 116 | }; 117 | 118 | NetFD* NewFD(AddressFamily family, int sotype, int* error_code = NULL); 119 | 120 | } // namespace net 121 | } // namespace tin 122 | -------------------------------------------------------------------------------- /tin/net/poll_desc.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include "tin/error/error.h" 8 | #include "tin/net/net.h" 9 | #include "tin/runtime/runtime.h" 10 | #include "tin/runtime/net/pollops.h" 11 | #include "tin/net/poll_desc.h" 12 | 13 | namespace tin { 14 | namespace net { 15 | 16 | namespace { 17 | int ConvertErr(int res) { 18 | switch (res) { 19 | case 0: 20 | return 0; 21 | case 1: 22 | return TIN_ECLOSE_INTR; 23 | case 2: 24 | return TIN_ETIMEOUT_INTR; 25 | } 26 | LOG(FATAL) << "unreachable error."; 27 | // unreachable. 28 | return 0; 29 | } 30 | } // namespace 31 | 32 | 33 | absl::once_flag server_init; 34 | 35 | int PollDesc::Init(uintptr_t sysfd) { 36 | absl::call_once(server_init, tin::runtime::pollops::ServerInit); 37 | int error_no = 0; 38 | runtime::PollDescriptor* ctx = runtime::pollops::Open(sysfd, &error_no); 39 | if (error_no == 0) { 40 | runtime_ctx_ = reinterpret_cast(ctx); 41 | } 42 | return error_no; 43 | } 44 | 45 | void PollDesc::Close() { 46 | if (runtime_ctx_ == 0) { 47 | return; 48 | } 49 | runtime::pollops::Close(Desc()); 50 | runtime_ctx_ = 0; 51 | } 52 | 53 | void PollDesc::Evict() { 54 | if (runtime_ctx_ == 0) { 55 | return; 56 | } 57 | runtime::pollops::Unblock(Desc()); 58 | } 59 | 60 | int PollDesc::Prepare(int mode) { 61 | int res = runtime::pollops::Reset(Desc(), mode); 62 | return ConvertErr(res); 63 | } 64 | 65 | int PollDesc::PrepareRead() { 66 | return Prepare('r'); 67 | } 68 | 69 | int PollDesc::PrepareWrite() { 70 | return Prepare('w'); 71 | } 72 | 73 | int PollDesc::Wait(int mode) { 74 | int res = runtime::pollops::Wait(Desc(), mode); 75 | return ConvertErr(res); 76 | } 77 | 78 | int PollDesc::WaitRead() { 79 | return Wait('r'); 80 | } 81 | 82 | int PollDesc::WaitWrite() { 83 | return Wait('w'); 84 | } 85 | 86 | void PollDesc::WaitCanceled(int mode) { 87 | runtime::pollops::WaitCanceled(Desc(), mode); 88 | } 89 | 90 | void PollDesc::WaitCanceledRead() { 91 | WaitCanceled('r'); 92 | } 93 | 94 | void PollDesc::WaitCanceledWrite() { 95 | WaitCanceled('w'); 96 | } 97 | 98 | } // namespace net 99 | } // namespace tin 100 | -------------------------------------------------------------------------------- /tin/net/poll_desc.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | 8 | namespace tin { 9 | 10 | // forward declaration. 11 | namespace runtime { 12 | struct PollDescriptor; 13 | } 14 | 15 | namespace net { 16 | 17 | class PollDesc { 18 | public: 19 | PollDesc() 20 | : runtime_ctx_(0) { 21 | } 22 | 23 | ~PollDesc() { 24 | } 25 | 26 | int Init(uintptr_t sysfd); 27 | void Close(); 28 | void Evict(); 29 | int Prepare(int mode); 30 | int PrepareRead(); 31 | int PrepareWrite(); 32 | int Wait(int mode); 33 | int WaitRead(); 34 | int WaitWrite(); 35 | void WaitCanceled(int mode); 36 | void WaitCanceledRead(); 37 | void WaitCanceledWrite(); 38 | inline tin::runtime::PollDescriptor* Desc() { 39 | return reinterpret_cast(runtime_ctx_); 40 | } 41 | uintptr_t DescAsUintptr() { 42 | return runtime_ctx_; 43 | } 44 | 45 | private: 46 | uintptr_t runtime_ctx_; 47 | }; 48 | 49 | } // namespace net 50 | } // namespace tin 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /tin/net/resolve.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "build/build_config.h" 6 | #if defined(OS_WIN) 7 | #include 8 | #include 9 | #else 10 | #include 11 | #include 12 | #include 13 | #endif 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include "tin/error/error.h" 21 | #include "tin/runtime/util.h" 22 | #include "tin/runtime/runtime.h" 23 | #include "tin/runtime/threadpoll.h" 24 | #include "tin/net/ip_endpoint.h" 25 | 26 | #include "tin/net/resolve.h" 27 | 28 | namespace tin { 29 | namespace net { 30 | 31 | using namespace runtime; // NOLINT 32 | 33 | int SyncResolveHostname(const absl::string_view& hostname, AddressFamily af, 34 | std::vector* addresses) { 35 | int family = ConvertAddressFamily(af); 36 | addresses->clear(); 37 | struct addrinfo* result = NULL; 38 | struct addrinfo hints = { 0 }; 39 | hints.ai_family = family; 40 | 41 | // The behavior of AF_UNSPEC is roughly "get both ipv4 and ipv6", as 42 | // documented by the various operating systems: 43 | // Linux: http://man7.org/linux/man-pages/man3/getaddrinfo.3.html 44 | // Windows: https://msdn.microsoft.com/en-us/library/windows/desktop/ 45 | // ms738520(v=vs.85).aspx 46 | // Mac: https://developer.apple.com/legacy/library/documentation/Darwin/ 47 | // Reference/ManPages/man3/getaddrinfo.3.html 48 | // Android (source code, not documentation): 49 | // https://android.googlesource.com/platform/bionic/+/ 50 | // 7e0bfb511e85834d7c6cb9631206b62f82701d60/libc/netbsd/net/getaddrinfo.c#1657 51 | hints.ai_flags = AI_ADDRCONFIG; 52 | int ret = getaddrinfo(hostname.data(), NULL, &hints, &result); 53 | if (ret != 0) { 54 | return ret; 55 | } 56 | struct addrinfo* cursor = result; 57 | for (; cursor; cursor = cursor->ai_next) { 58 | if (family == AF_UNSPEC || cursor->ai_family == family) { 59 | IPEndPoint endpoint; 60 | if (endpoint.FromSockAddr(cursor->ai_addr, 61 | static_cast(cursor->ai_addrlen))) { 62 | addresses->push_back(endpoint.address()); 63 | } 64 | } 65 | } 66 | freeaddrinfo(result); 67 | return 0; 68 | } 69 | 70 | class ResolveHostnameWork : public GletWork { 71 | public: 72 | ResolveHostnameWork(const absl::string_view& hostname, // NOLINT 73 | AddressFamily& family, // NOLINT 74 | std::vector*& addresses) // NOLINT 75 | : result_(0) 76 | , hostname_(hostname) 77 | , family_(family) 78 | , addresses_(addresses) { 79 | } 80 | 81 | virtual ~ResolveHostnameWork() { } 82 | 83 | virtual void Run() { 84 | result_ = SyncResolveHostname(hostname_, family_, addresses_); 85 | Finalize(); 86 | } 87 | 88 | int Result() { 89 | return result_; 90 | } 91 | 92 | private: 93 | int result_; 94 | const absl::string_view& hostname_; 95 | AddressFamily& family_; 96 | std::vector*& addresses_; 97 | }; 98 | 99 | int ResolveHostname(const absl::string_view& hostname, 100 | AddressFamily family, 101 | std::vector* addresses) { 102 | if (addresses == NULL) { 103 | tin::SetErrorCode(TIN_EINVAL); 104 | return -1; 105 | } 106 | std::unique_ptr work( 107 | new ResolveHostnameWork(hostname, family, addresses)); 108 | SubmitGetAddrInfoGletWork(work.get()); 109 | return work->Result(); 110 | } 111 | 112 | // handy functions. 113 | tin::net::IPAddress ResolveHostname(const absl::string_view& hostname, 114 | AddressFamily af) { 115 | std::vector addresses; 116 | if (ResolveHostname(hostname, af, &addresses) == 0) { 117 | if (addresses.empty()) { 118 | // must not be empty on success 119 | LOG(FATAL) << "ResolveHostname return empty list on success"; 120 | } 121 | return addresses.front(); 122 | } 123 | return IPAddress(); 124 | } 125 | 126 | IPAddress ResolveHostname(const absl::string_view& hostname) { 127 | return ResolveHostname(hostname, ADDRESS_FAMILY_UNSPECIFIED); 128 | } 129 | 130 | IPAddress ResolveHostname4(const absl::string_view& hostname) { 131 | return ResolveHostname(hostname, ADDRESS_FAMILY_IPV4); 132 | } 133 | 134 | IPAddress ResolveHostname6(const absl::string_view& hostname) { 135 | return ResolveHostname(hostname, ADDRESS_FAMILY_IPV6); 136 | } 137 | 138 | } // namespace net 139 | } // namespace tin 140 | 141 | -------------------------------------------------------------------------------- /tin/net/resolve.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include 10 | #include "tin/net/address_family.h" 11 | #include "tin/net/ip_address.h" 12 | 13 | namespace tin { 14 | namespace net { 15 | 16 | int ResolveHostname(const absl::string_view& hostname, AddressFamily af, 17 | std::vector* addresses); 18 | 19 | IPAddress ResolveHostname4(const absl::string_view& hostname); 20 | 21 | IPAddress ResolveHostname6(const absl::string_view& hostname); 22 | 23 | IPAddress ResolveHostname(const absl::string_view& hostname); 24 | 25 | IPAddress ResolveHostname(const absl::string_view& hostname); 26 | 27 | IPAddress ResolveHostname(const absl::string_view& hostname, AddressFamily af); 28 | 29 | } // namespace net 30 | } // namespace tin 31 | 32 | -------------------------------------------------------------------------------- /tin/net/sockaddr_storage.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "tin/net/sockaddr_storage.h" 6 | 7 | #include 8 | 9 | namespace tin { 10 | namespace net { 11 | 12 | SockaddrStorage::SockaddrStorage() 13 | : addr_len(sizeof(addr_storage)), 14 | addr(reinterpret_cast(&addr_storage)) {} 15 | 16 | SockaddrStorage::SockaddrStorage(const SockaddrStorage& other) 17 | : addr_len(other.addr_len), 18 | addr(reinterpret_cast(&addr_storage)) { 19 | memcpy(addr, other.addr, addr_len); 20 | } 21 | 22 | void SockaddrStorage::operator=(const SockaddrStorage& other) { 23 | addr_len = other.addr_len; 24 | // addr is already set to &this->addr_storage by default ctor. 25 | memcpy(addr, other.addr, addr_len); 26 | } 27 | 28 | } // namespace net 29 | } // namespace tin 30 | -------------------------------------------------------------------------------- /tin/net/sockaddr_storage.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef NET_BASE_SOCKADDR_STORAGE_H_ 6 | #define NET_BASE_SOCKADDR_STORAGE_H_ 7 | 8 | #include "build/build_config.h" 9 | 10 | #if defined(OS_POSIX) 11 | #include 12 | #include 13 | #elif defined(OS_WIN) 14 | #include 15 | #include 16 | #endif 17 | 18 | namespace tin { 19 | namespace net { 20 | 21 | // Convenience struct for when you need a |struct sockaddr|. 22 | struct SockaddrStorage { 23 | SockaddrStorage(); 24 | SockaddrStorage(const SockaddrStorage& other); 25 | void operator=(const SockaddrStorage& other); 26 | 27 | struct sockaddr_storage addr_storage; 28 | socklen_t addr_len; 29 | struct sockaddr* const addr; 30 | }; 31 | 32 | } // namespace net 33 | } // namespace tin 34 | 35 | #endif // NET_BASE_SOCKADDR_STORAGE_H_ 36 | -------------------------------------------------------------------------------- /tin/net/sys_addrinfo.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // This is a convenience header to pull in the platform-specific headers 6 | // that define at least: 7 | // 8 | // struct addrinfo 9 | // struct sockaddr* 10 | // getaddrinfo() 11 | // freeaddrinfo() 12 | // AI_* 13 | // AF_* 14 | // 15 | // Prefer including this file instead of directly writing the #if / #else, 16 | // since it avoids duplicating the platform-specific selections. 17 | 18 | #include "build/build_config.h" 19 | 20 | #if defined(OS_WIN) 21 | #include 22 | #elif defined(OS_POSIX) 23 | #include 24 | #include 25 | #include 26 | #endif 27 | -------------------------------------------------------------------------------- /tin/net/sys_socket.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #ifndef NATIVE_CLIENT_SRC_INCLUDE_PORTABILITY_SOCKETS_H_ 8 | #define NATIVE_CLIENT_SRC_INCLUDE_PORTABILITY_SOCKETS_H_ 1 9 | 10 | #include "build/build_config.h" 11 | 12 | #if defined(OS_WIN) 13 | 14 | #include 15 | #include 16 | #include 17 | #else 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #endif 26 | 27 | #endif // NATIVE_CLIENT_SRC_INCLUDE_PORTABILITY_SOCKETS_H_ 28 | -------------------------------------------------------------------------------- /tin/net/tcp_conn.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "build/build_config.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include "tin/net/sys_socket.h" 11 | #include "tin/error/error.h" 12 | #include "tin/time/time.h" 13 | #include "tin/runtime/runtime.h" 14 | #include "tin/net/netfd.h" 15 | #include "tin/net/tcp_conn.h" 16 | 17 | namespace tin { 18 | namespace net { 19 | 20 | TcpConnImpl::TcpConnImpl(NetFD* netfd) 21 | : netfd_(netfd) , 22 | total_read_bytes_(0) { 23 | } 24 | 25 | TcpConnImpl::~TcpConnImpl() { 26 | delete netfd_; 27 | } 28 | 29 | int TcpConnImpl::Read(void* buf, int nbytes) { 30 | LOG_IF(FATAL, nbytes == 0) << "Read on zero buffer."; 31 | int nread = 0; 32 | int err = netfd_->Read(buf, nbytes, &nread); 33 | tin::SetErrorCode(TinTranslateSysError(err)); 34 | if (nread > 0) { 35 | total_read_bytes_ += total_read_bytes_; 36 | } 37 | return nread; 38 | } 39 | 40 | int TcpConnImpl::Write(const void* buf, int nbytes) { 41 | LOG_IF(FATAL, nbytes == 0) << "Write on zero buffer."; 42 | int nwritten = 0; 43 | int err = netfd_->Write(buf, nbytes, &nwritten); 44 | tin::SetErrorCode(TinTranslateSysError(err)); 45 | return nwritten; 46 | } 47 | 48 | void TcpConnImpl::SetDeadline(int64_t t) { 49 | netfd_->SetDeadline(t); 50 | } 51 | 52 | void TcpConnImpl::SetReadDeadline(int64_t t) { 53 | netfd_->SetReadDeadline(t); 54 | } 55 | 56 | void TcpConnImpl::SetWriteDeadline(int64_t t) { 57 | netfd_->SetWriteDeadline(t); 58 | } 59 | 60 | bool TcpConnImpl::SetKeepAlive(bool enable, int sec) { 61 | int err = netfd_->SetTCPKeepAlive(enable, sec); 62 | err = TinTranslateSysError(err); 63 | tin::SetErrorCode(err); 64 | return err == 0; 65 | } 66 | 67 | void TcpConnImpl::SetLinger(int sec) { 68 | #if defined(OS_WIN) 69 | LINGER linger = { 0 }; 70 | #else 71 | struct linger linger = { 0 }; 72 | #endif 73 | if (sec >= 0) { 74 | linger.l_onoff = 1; 75 | linger.l_linger = sec; 76 | } 77 | (void)SetSockOpt(SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); 78 | } 79 | 80 | void TcpConnImpl::SetNoDelay(bool no_delay) { 81 | // Microsoft Windows disable TCP_NODELAY default. 82 | int on = no_delay ? 1 : 0; 83 | (void)SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); 84 | } 85 | 86 | void TcpConnImpl::SetReadBuffer(int bytes) { 87 | (void)SetSockOpt(SOL_SOCKET, SO_RCVBUF, &bytes, sizeof(bytes)); 88 | } 89 | 90 | void TcpConnImpl::SetWriteBuffer(int bytes) { 91 | (void)SetSockOpt(SOL_SOCKET, SO_SNDBUF, &bytes, sizeof(bytes)); 92 | } 93 | 94 | bool TcpConnImpl::GetSockOpt(int level, 95 | int name, 96 | void* optval, 97 | socklen_t* optlen) { 98 | int err = netfd_->GetSockOpt(level, name, optval, optlen); 99 | err = TinTranslateSysError(err); 100 | tin::SetErrorCode(err); 101 | return err == 0; 102 | } 103 | 104 | bool TcpConnImpl::SetSockOpt(int level, 105 | int name, 106 | const void* optval, 107 | socklen_t optlen) { 108 | int err = netfd_->SetSockOpt(level, name, optval, optlen); 109 | err = TinTranslateSysError(err); 110 | tin::SetErrorCode(err); 111 | return err == 0; 112 | } 113 | 114 | void TcpConnImpl::CloseRead() { 115 | int err = netfd_->CloseRead(); 116 | tin::SetErrorCode(err); 117 | } 118 | 119 | void TcpConnImpl::CloseWrite() { 120 | int err = netfd_->CloseWrite(); 121 | tin::SetErrorCode(err); 122 | } 123 | 124 | void TcpConnImpl::Close() { 125 | netfd_->Close(); 126 | } 127 | 128 | } // namespace net 129 | } // namespace tin 130 | -------------------------------------------------------------------------------- /tin/net/tcp_conn.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include "tin/time/time.h" 10 | #include "tin/io/io.h" 11 | 12 | namespace tin { 13 | namespace net { 14 | 15 | class NetFD; 16 | 17 | class TcpConnImpl 18 | : public std::enable_shared_from_this 19 | , public tin::io::IOReadWriter { 20 | public: 21 | explicit TcpConnImpl(NetFD* netfd); 22 | 23 | virtual ~TcpConnImpl(); 24 | 25 | TcpConnImpl(const TcpConnImpl&) = delete; 26 | TcpConnImpl& operator=(const TcpConnImpl&) = delete; 27 | 28 | // note: Read full or partial on success, or read partial on failure. 29 | // return value : indicate n bytes written. n >= 0. 30 | // don't handle error based on return value. 31 | // detail error, see tin::GetErrorCode() 32 | int Read(void* buf, int nbytes); 33 | 34 | // note: Write full on success, or write partial on failure. 35 | // return value : indicate n bytes written. n >= 0. 36 | // don't handle error based on return value. 37 | // detail error, see tin::GetErrorCode() 38 | int Write(const void* buf, int nbytes); 39 | 40 | void SetDeadline(int64_t t); 41 | 42 | void SetReadDeadline(int64_t t); 43 | 44 | void SetWriteDeadline(int64_t t); 45 | 46 | bool SetKeepAlive(bool enable, int sec); 47 | 48 | void SetLinger(int sec); 49 | 50 | void SetNoDelay(bool no_delay); 51 | 52 | void SetReadBuffer(int bytes); 53 | 54 | void SetWriteBuffer(int bytes); 55 | 56 | bool GetSockOpt(int level, int name, void* optval, socklen_t* optlen); 57 | 58 | bool SetSockOpt(int level, int name, const void* optval, socklen_t optlen); 59 | 60 | void CloseRead(); 61 | 62 | void CloseWrite(); 63 | 64 | void Close(); 65 | 66 | int64_t TotalReadBytes() const { 67 | return total_read_bytes_; 68 | } 69 | 70 | private: 71 | NetFD* netfd_; 72 | int64_t total_read_bytes_; 73 | }; 74 | 75 | 76 | class TcpConn { 77 | public: 78 | TcpConn(TcpConnImpl* conn) 79 | : impl_(conn) { 80 | } 81 | 82 | TcpConn(const TcpConn& other) 83 | : impl_(other.impl_) { 84 | } 85 | 86 | TcpConnImpl* operator->() { 87 | return impl_.get(); 88 | } 89 | 90 | private: 91 | std::shared_ptr impl_; 92 | }; 93 | 94 | inline TcpConn MakeTcpConn(TcpConnImpl* conn) { 95 | return {conn}; 96 | } 97 | 98 | } // namespace net 99 | } // namespace tin 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /tin/net/winsock_util.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include "tin/net/winsock_util.h" 7 | 8 | 9 | namespace tin { 10 | namespace net { 11 | 12 | namespace { 13 | 14 | // Prevent the compiler from optimizing away the arguments so they appear 15 | // nicely on the stack in crash dumps. 16 | #pragma warning(push) 17 | #pragma warning(disable: 4748) 18 | #pragma optimize("", off) 19 | 20 | // Pass the important values as function arguments so that they are available 21 | // in crash dumps. 22 | void CheckEventWait(WSAEVENT hEvent, DWORD wait_rv, DWORD expected) { 23 | if (wait_rv != expected) { 24 | DWORD err = ERROR_SUCCESS; 25 | if (wait_rv == WAIT_FAILED) 26 | err = GetLastError(); 27 | CHECK(false); // Crash. 28 | } 29 | } 30 | 31 | #pragma optimize("", on) 32 | #pragma warning(pop) 33 | 34 | } // namespace 35 | 36 | void AssertEventNotSignaled(WSAEVENT hEvent) { 37 | DWORD wait_rv = WaitForSingleObject(hEvent, 0); 38 | CheckEventWait(hEvent, wait_rv, WAIT_TIMEOUT); 39 | } 40 | 41 | bool ResetEventIfSignaled(WSAEVENT hEvent) { 42 | DWORD wait_rv = WaitForSingleObject(hEvent, 0); 43 | if (wait_rv == WAIT_TIMEOUT) 44 | return false; // The event object is not signaled. 45 | CheckEventWait(hEvent, wait_rv, WAIT_OBJECT_0); 46 | BOOL ok = WSAResetEvent(hEvent); 47 | CHECK(ok); 48 | return true; 49 | } 50 | 51 | } // namespace net 52 | } // namespace tin 53 | -------------------------------------------------------------------------------- /tin/net/winsock_util.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | 6 | #ifndef NET_BASE_WINSOCK_UTIL_H_ 7 | #define NET_BASE_WINSOCK_UTIL_H_ 8 | 9 | #include 10 | #include 11 | 12 | namespace tin { 13 | namespace net { 14 | 15 | // Bluetooth address size. Windows Bluetooth is supported via winsock. 16 | static const size_t kBluetoothAddressSize = 6; 17 | 18 | // Assert that the (manual-reset) event object is not signaled. 19 | void AssertEventNotSignaled(WSAEVENT hEvent); 20 | 21 | // If the (manual-reset) event object is signaled, resets it and returns true. 22 | // Otherwise, does nothing and returns false. Called after a Winsock function 23 | // succeeds synchronously 24 | // 25 | // Our testing shows that except in rare cases (when running inside QEMU), 26 | // the event object is already signaled at this point, so we call this method 27 | // to avoid a context switch in common cases. This is just a performance 28 | // optimization. The code still works if this function simply returns false. 29 | bool ResetEventIfSignaled(WSAEVENT hEvent); 30 | 31 | } // namespace net 32 | } // namespace tin 33 | 34 | #endif // NET_BASE_WINSOCK_UTIL_H_ 35 | -------------------------------------------------------------------------------- /tin/platform/platform.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | namespace tin { 8 | // each platform should implement the fellowing two functions. 9 | bool PlatformInit(); 10 | void PlatformDeinit(); 11 | 12 | } 13 | 14 | -------------------------------------------------------------------------------- /tin/platform/platform_posix.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include "tin/platform/platform.h" 7 | #include "tin/platform/platform_posix.h" 8 | 9 | namespace tin { 10 | 11 | bool PlatformInit() { 12 | return true; 13 | } 14 | 15 | void PlatformDeinit() { 16 | } 17 | 18 | } // namespace tin 19 | -------------------------------------------------------------------------------- /tin/platform/platform_posix.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include "build/build_config.h" 10 | #include "cstdint" 11 | 12 | namespace tin { 13 | 14 | #if defined(OS_LINUX) 15 | 16 | #if defined(__alpha__) 17 | # define TIN__O_CLOEXEC 0x200000 18 | #elif defined(__hppa__) 19 | # define TIN__O_CLOEXEC 0x200000 20 | #elif defined(__sparc__) 21 | # define TIN__O_CLOEXEC 0x400000 22 | #else 23 | # define TIN__O_CLOEXEC 0x80000 24 | #endif 25 | 26 | #if defined(__alpha__) 27 | # define TIN__O_NONBLOCK 0x4 28 | #elif defined(__hppa__) 29 | # define TIN__O_NONBLOCK O_NONBLOCK 30 | #elif defined(__mips__) 31 | # define TIN__O_NONBLOCK 0x80 32 | #elif defined(__sparc__) 33 | # define TIN__O_NONBLOCK 0x4000 34 | #else 35 | # define TIN__O_NONBLOCK 0x800 36 | #endif 37 | 38 | #define TIN__EFD_CLOEXEC TIN__O_CLOEXEC 39 | #define TIN__EFD_NONBLOCK TIN__O_NONBLOCK 40 | 41 | #define TIN__IN_CLOEXEC TIN__O_CLOEXEC 42 | #define TIN__IN_NONBLOCK TIN__O_NONBLOCK 43 | 44 | #define TIN__SOCK_CLOEXEC TIN__O_CLOEXEC 45 | #if defined(SOCK_NONBLOCK) 46 | # define TIN__SOCK_NONBLOCK SOCK_NONBLOCK 47 | #else 48 | # define TIN__SOCK_NONBLOCK TIN__O_NONBLOCK 49 | #endif 50 | 51 | #if defined(__arm__) 52 | # if defined(__thumb__) || defined(__ARM_EABI__) 53 | # define TIN_SYSCALL_BASE 0 54 | # else 55 | # define TIN_SYSCALL_BASE 0x900000 56 | # endif 57 | #endif /* __arm__ */ 58 | 59 | #ifndef __NR_accept4 60 | # if defined(__x86_64__) 61 | # define __NR_accept4 288 62 | # elif defined(__i386__) 63 | /* Nothing. Handled through socketcall(). */ 64 | # elif defined(__arm__) 65 | # define __NR_accept4 (TIN_SYSCALL_BASE + 366) 66 | # endif 67 | #endif /* __NR_accept4 */ 68 | 69 | #endif // #if defined(OS_LINUX) 70 | 71 | } // namespace tin 72 | 73 | -------------------------------------------------------------------------------- /tin/platform/platform_win.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include "tin/platform/platform.h" 9 | #include "tin/platform/platform_win.h" 10 | 11 | namespace tin { 12 | 13 | bool flag_cancelioex_avaiable; // determines if CancelIoEx API is present 14 | bool global_skip_sync_notificaton; 15 | bool hasLoadSetFileCompletionNotificationModes; 16 | 17 | bool CanUseConnectEx(const std::string& net) { 18 | if (net == "udp" || 19 | net == "udp4" || 20 | net == "udp6" || 21 | net == "ip" || 22 | net == "ip4" || 23 | net == "ip6") { 24 | return false; 25 | } 26 | return pConnectEx != NULL; 27 | } 28 | 29 | static BOOL TinGetExtensionFunction(SOCKET socket, GUID guid, 30 | void** target) { 31 | int result; 32 | DWORD bytes; 33 | 34 | result = WSAIoctl(socket, 35 | SIO_GET_EXTENSION_FUNCTION_POINTER, 36 | &guid, 37 | sizeof(guid), 38 | static_cast(target), 39 | sizeof(*target), 40 | &bytes, 41 | NULL, 42 | NULL); 43 | 44 | if (result == SOCKET_ERROR) { 45 | *target = NULL; 46 | return FALSE; 47 | } else { 48 | return TRUE; 49 | } 50 | } 51 | 52 | bool PlatformInit() { 53 | HMODULE ntdll_module; 54 | HMODULE kernel32_module; 55 | 56 | ntdll_module = GetModuleHandleA("ntdll.dll"); 57 | if (ntdll_module == NULL) { 58 | return false; 59 | } 60 | 61 | kernel32_module = GetModuleHandleA("kernel32.dll"); 62 | if (kernel32_module == NULL) { 63 | return false; 64 | } 65 | 66 | pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx)GetProcAddress( 67 | kernel32_module, 68 | "GetQueuedCompletionStatusEx"); 69 | 70 | WSADATA wsaData; 71 | WSAStartup(MAKEWORD(2, 2), &wsaData); 72 | 73 | pCancelIoEx = (sCancelIoEx) 74 | GetProcAddress(kernel32_module, "CancelIoEx"); 75 | 76 | flag_cancelioex_avaiable = (pCancelIoEx != NULL); 77 | { 78 | SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 79 | GUID guid = WSAID_CONNECTEX; 80 | TinGetExtensionFunction(s, guid, (void**)&pConnectEx); // NOLINT 81 | closesocket(s); 82 | } 83 | 84 | pSetFileCompletionNotificationModes = 85 | (sSetFileCompletionNotificationModes) 86 | GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes"); 87 | 88 | if (pSetFileCompletionNotificationModes) { 89 | hasLoadSetFileCompletionNotificationModes = true; 90 | // It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 91 | // if non IFS providers are installed: 92 | // http://support.microsoft.com/kb/2568167 93 | global_skip_sync_notificaton = true; 94 | 95 | int32_t protos[2] = { IPPROTO_TCP, 0 }; 96 | WSAPROTOCOL_INFO buf[32]; 97 | DWORD len = sizeof(buf); 98 | int n = WSAEnumProtocols(&protos[0], &buf[0], &len); 99 | if (n == SOCKET_ERROR) { 100 | global_skip_sync_notificaton = false; 101 | } else { 102 | for (int i = 0; i < n; i++) { 103 | if ((buf[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0) { 104 | global_skip_sync_notificaton = false; 105 | break; 106 | } 107 | } 108 | } 109 | } 110 | return true; 111 | } 112 | 113 | void PlatformDeinit() { 114 | } 115 | 116 | sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx = NULL; 117 | sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes = NULL; 118 | sCancelIoEx pCancelIoEx = NULL; 119 | LPFN_CONNECTEX pConnectEx = NULL; 120 | 121 | } // namespace tin 122 | -------------------------------------------------------------------------------- /tin/platform/platform_win.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "build/build_config.h" 12 | #include "cstdint" 13 | 14 | #ifndef _In_reads_bytes_ 15 | #define _In_reads_bytes_(s) 16 | #endif 17 | #ifndef _In_reads_bytes_opt_ 18 | #define _In_reads_bytes_opt_(s) 19 | #endif 20 | 21 | namespace tin { 22 | 23 | typedef BOOL(WINAPI* sGetQueuedCompletionStatusEx) 24 | (HANDLE CompletionPort, 25 | LPOVERLAPPED_ENTRY lpCompletionPortEntries, 26 | ULONG ulCount, 27 | PULONG ulNumEntriesRemoved, 28 | DWORD dwMilliseconds, 29 | BOOL fAlertable); 30 | 31 | typedef BOOL(WINAPI* sCancelIoEx) 32 | (HANDLE hFile, 33 | LPOVERLAPPED lpOverlapped); 34 | 35 | typedef BOOL(WINAPI* sSetFileCompletionNotificationModes) 36 | (HANDLE FileHandle, 37 | UCHAR Flags); 38 | 39 | typedef 40 | BOOL 41 | (PASCAL FAR* LPFN_CONNECTEX) ( 42 | _In_ SOCKET s, 43 | _In_reads_bytes_(namelen) const struct sockaddr FAR* name, 44 | _In_ int namelen, 45 | _In_reads_bytes_opt_(dwSendDataLength) PVOID lpSendBuffer, 46 | _In_ DWORD dwSendDataLength, 47 | _Out_ LPDWORD lpdwBytesSent, 48 | _Inout_ LPOVERLAPPED lpOverlapped 49 | ); 50 | 51 | 52 | extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; 53 | extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; 54 | extern sCancelIoEx pCancelIoEx; 55 | extern LPFN_CONNECTEX pConnectEx; 56 | // determines if CancelIoEx API is present 57 | extern bool flag_cancelioex_avaiable; 58 | extern bool global_skip_sync_notificaton; 59 | extern bool hasLoadSetFileCompletionNotificationModes; 60 | 61 | bool CanUseConnectEx(const std::string& net); 62 | 63 | typedef uintptr_t syshandle; 64 | 65 | } // namespace tin 66 | 67 | -------------------------------------------------------------------------------- /tin/runtime/env.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "build/build_config.h" 10 | 11 | #include 12 | 13 | #include "tin/runtime/util.h" 14 | #include "tin/runtime/timer/timer_queue.h" 15 | #include "tin/runtime/greenlet.h" 16 | #include "tin/runtime/m.h" 17 | #include "tin/runtime/threadpoll.h" 18 | #include "tin/runtime/scheduler.h" 19 | #include "tin/runtime/sysmon.h" 20 | 21 | #include "tin/runtime/env.h" 22 | 23 | namespace tin { 24 | namespace runtime { 25 | 26 | Env::Env() 27 | : argc_(0) 28 | , argv_(NULL) 29 | , main_signal_(false) { 30 | } 31 | 32 | void Env::PreInit() { 33 | num_processors_ = static_cast(std::thread::hardware_concurrency()); 34 | } 35 | 36 | int Env::Initialize(EntryFn fn, int argc, char** argv, tin::Config* new_conf) { 37 | PreInit(); 38 | fn_ = fn; 39 | conf_ = new_conf; 40 | rtm_conf = conf_; 41 | SignalInit(); 42 | sched = new Scheduler; 43 | timer_q = new TimerQueue; 44 | glet_tls = new Greenlet; 45 | ThreadPoll::GetInstance()->Start(); 46 | M::New(absl::bind_front(&SysInit), NULL); 47 | 48 | return 0; 49 | } 50 | 51 | void Env::Deinitialize() { 52 | // don't delete rtm_config. 53 | delete timer_q; 54 | } 55 | 56 | int Env::WaitMainExit() { 57 | main_signal_.WaitForNotification(); 58 | return 0; 59 | } 60 | 61 | void Env::SysInit() { 62 | GetM()->SetM0Flag(); 63 | sched->Init(); 64 | SpawnSimple(&MainGlet, NULL, "main"); 65 | M::New(absl::bind_front(&SysMon), NULL); 66 | } 67 | 68 | void* Env::MainGlet(intptr_t) { 69 | rtm_env->fn_(rtm_env->argc_, rtm_env->argv_); 70 | rtm_env->OnMainExit(); 71 | return NULL; 72 | } 73 | 74 | void Env::OnMainExit() { 75 | // current workaround, exit directly. 76 | _exit(0); 77 | // TODO(author) wait for all exit, thread pool, net poller etc. 78 | exit_flag_ = true; 79 | ThreadPoll::GetInstance()->JoinAll(); 80 | timer_q->Join(); 81 | rtm_env->main_signal_.Notify(); 82 | } 83 | 84 | void Env::SignalInit() { 85 | // signal(SIGPIPE, SIG_IGN). 86 | #if defined(OS_POSIX) 87 | if (rtm_conf->IgnoreSigpipe()) { 88 | struct sigaction sigpipe_action; 89 | memset(&sigpipe_action, 0, sizeof(sigpipe_action)); 90 | sigpipe_action.sa_handler = SIG_IGN; 91 | sigemptyset(&sigpipe_action.sa_mask); 92 | bool success = (sigaction(SIGPIPE, &sigpipe_action, NULL) == 0); 93 | DCHECK(success); 94 | } 95 | #endif 96 | } 97 | 98 | int InitializeEnv(EntryFn fn, int argc, char** argv, tin::Config* new_conf) { 99 | rtm_env = new Env; 100 | rtm_env->Initialize(fn, argc, argv, new_conf); 101 | return 0; 102 | } 103 | 104 | void DeInitializeEnv() { 105 | rtm_env->Deinitialize(); 106 | } 107 | 108 | Env* rtm_env = NULL; 109 | Scheduler* sched = NULL; 110 | TimerQueue* timer_q = NULL; 111 | thread_local Greenlet* glet_tls = NULL; 112 | 113 | tin::Config* rtm_conf = NULL; 114 | 115 | } // namespace runtime 116 | } // namespace tin 117 | -------------------------------------------------------------------------------- /tin/runtime/env.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include "absl/synchronization/notification.h" 8 | 9 | #include "tin/tin.h" 10 | #include "tin/sync/atomic_flag.h" 11 | #include "tin/config/config.h" 12 | 13 | namespace tin { 14 | namespace runtime { 15 | 16 | class Env { 17 | public: 18 | Env(); 19 | Env(const Env&) = delete; 20 | Env& operator=(const Env&) = delete; 21 | int Initialize(EntryFn fn, int argc, char** argv, Config* new_conf); 22 | void Deinitialize(); 23 | tin::Config* GetConfig() const { 24 | return conf_; 25 | } 26 | int NumberOfProcessors() { 27 | return num_processors_; 28 | } 29 | int WaitMainExit(); 30 | bool ExitFlag() const { 31 | return exit_flag_ == true; 32 | } 33 | 34 | private: 35 | void SignalInit(); 36 | void PreInit(); 37 | static void SysInit(); 38 | static void* MainGlet(intptr_t); 39 | void OnMainExit(); 40 | 41 | private: 42 | EntryFn fn_; 43 | int argc_; 44 | char** argv_; 45 | tin::Config* conf_; 46 | int num_processors_; 47 | absl::Notification main_signal_; 48 | tin::AtomicFlag exit_flag_; 49 | }; 50 | 51 | class Scheduler; 52 | class Greenlet; 53 | class TimerQueue; 54 | 55 | extern Env* rtm_env; 56 | extern Scheduler* sched; 57 | extern TimerQueue* timer_q; 58 | extern thread_local Greenlet* glet_tls; 59 | extern tin::Config* rtm_conf; 60 | 61 | int InitializeEnv(EntryFn fn, int argc, char** argv, Config* new_conf); 62 | void DeInitializeEnv(); 63 | 64 | 65 | } // namespace runtime 66 | } // namespace tin 67 | -------------------------------------------------------------------------------- /tin/runtime/greenlet.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "context/zcontext.h" 11 | #include "tin/runtime/m.h" 12 | #include "tin/runtime/p.h" 13 | #include "tin/runtime/scheduler.h" 14 | #include "tin/runtime/timer/timer_queue.h" 15 | 16 | #include "tin/runtime/greenlet.h" 17 | 18 | namespace tin { 19 | namespace runtime { 20 | 21 | Greenlet::Greenlet() 22 | : lockedm_(NULL) 23 | , error_code_(0) 24 | , timer_(NULL) { 25 | } 26 | 27 | Greenlet::~Greenlet() { 28 | delete timer_; 29 | } 30 | 31 | void Greenlet::SetName(const char* name) { 32 | // TODO 33 | if (name != NULL) 34 | cliff::strlcpy(name_, name, ABSL_ARRAYSIZE(name_)); 35 | else 36 | cliff::strlcpy(name_, "greenlet", ABSL_ARRAYSIZE(name_)); 37 | } 38 | 39 | Timer* Greenlet::GetTimer() { 40 | if (timer_ == NULL) { 41 | timer_ = new Timer; 42 | } 43 | return timer_; 44 | } 45 | 46 | 47 | 48 | 49 | Greenlet* Greenlet::Create(GreenletFunc entry, 50 | std::function* closure, 51 | bool sysg0 /*= false*/, 52 | intptr_t args /*= 0*/, 53 | bool joinable /*= false*/, 54 | int stack_size /*= kDefaultStackSize*/, 55 | const char* name /*= "greenlet"*/) { 56 | // joinable, not implement 57 | if (stack_size == 0) 58 | stack_size = kDefaultStackSize; 59 | std::unique_ptr glet(new Greenlet); 60 | { 61 | glet->flags_ = 0; 62 | glet->args_ = 0; 63 | } 64 | glet->state_ = GLET_RUNNABLE; 65 | glet->args_ = args; 66 | glet->entry_ = entry; 67 | if (closure != NULL) { 68 | std::swap(glet->closure_, *closure); 69 | } 70 | glet->SetName(name); 71 | if (rtm_conf->IsStackProtectionEnabled()) { 72 | glet->stack_.reset(NewStack(kProtectedFixedStack, stack_size)); 73 | } else { 74 | glet->stack_.reset(NewStack(kFixedStack, stack_size)); 75 | } 76 | // make_zcontext round address internally. 77 | glet->context_ = 78 | make_zcontext(glet->stack_->Pointer(), stack_size, StaticProc); 79 | if (!sysg0) { 80 | GetP()->RunqPut(glet.get(), true); 81 | sched->WakePIfNecessary(); 82 | } else { 83 | glet->SetG0Flag(); 84 | glet_tls = glet.get(); 85 | } 86 | return glet.release(); 87 | } 88 | 89 | void Greenlet::StaticProc(intptr_t args) { 90 | Greenlet* glet = reinterpret_cast(args); 91 | glet->Proc(); 92 | } 93 | 94 | void Greenlet::Proc() { 95 | if (closure_) { 96 | closure_(); 97 | } else { 98 | retval_ = entry_(args_); 99 | } 100 | 101 | // glet exit. 102 | // add to m local dead queue. 103 | M()->AddToDeadQueue(this); 104 | Park(); 105 | // never return. 106 | } 107 | 108 | void SpawnSimple(GreenletFunc entry, void* args, const char* name) { 109 | Greenlet::Create(entry, 110 | NULL, 111 | false, 112 | reinterpret_cast(args), 113 | false, 114 | 0, 115 | name); 116 | } 117 | 118 | void SpawnSimple(std::function closure, const char* name) { 119 | Greenlet::Create(NULL, 120 | &closure, 121 | false, 122 | 0, 123 | false, 124 | 0, 125 | name); 126 | } 127 | 128 | 129 | } // namespace runtime 130 | 131 | void RuntimeSpawn(std::function* closure) { 132 | runtime::Greenlet::Create(NULL, 133 | closure, 134 | false, 135 | 0, 136 | false, 137 | 0); 138 | } 139 | 140 | } // namespace tin 141 | -------------------------------------------------------------------------------- /tin/runtime/greenlet.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include 10 | #include "context/zcontext.h" 11 | #include "tin/config/config.h" 12 | #include "tin/runtime/util.h" 13 | #include "tin/runtime/guintptr.h" 14 | #include "tin/runtime/stack/stack.h" 15 | 16 | namespace tin { 17 | namespace runtime { 18 | 19 | class M; 20 | struct Timer; 21 | 22 | enum GletState { 23 | GLET_RUNNING = 0, 24 | GLET_RUNNABLE = 1, 25 | GLET_WAITING = 2, 26 | GLET_SYSCALL = 3, 27 | GLET_EXITED = 4 28 | }; 29 | 30 | enum GreenletFlag { 31 | kGletFlagG0 = 1, 32 | }; 33 | 34 | typedef void* (*GreenletFunc)(intptr_t); 35 | 36 | class Greenlet { 37 | public: 38 | Greenlet(); 39 | Greenlet(const Greenlet&) = delete; 40 | Greenlet& operator=(const Greenlet&) = delete; 41 | 42 | ~Greenlet(); 43 | 44 | void SetSchedLink(G* gp) { 45 | schedlink_ = gp; 46 | } 47 | uintptr_t SchedLink() const { 48 | return schedlink_.Integer(); 49 | } 50 | 51 | tin::runtime::M* M() const { 52 | return m_; 53 | } 54 | 55 | void SetM(tin::runtime::M* m) { 56 | m_ = m; 57 | } 58 | 59 | tin::runtime::M* LockedM() const { 60 | return lockedm_; 61 | } 62 | 63 | void SetLockedM(tin::runtime::M* m) { 64 | lockedm_ = m; 65 | } 66 | 67 | int GetState() const { 68 | return state_; 69 | } 70 | 71 | void SetState(int state) { 72 | state_ = state; 73 | } 74 | 75 | void SetName(const char* name); 76 | 77 | const char* GetName() { 78 | return name_; 79 | } 80 | 81 | zcontext_t* MutableContext() { 82 | return &context_; 83 | } 84 | 85 | int GetErrorCode() { 86 | return error_code_; 87 | } 88 | 89 | void SetErrorCode(int error_code) { 90 | error_code_ = error_code; 91 | } 92 | 93 | void SetG0Flag() { 94 | flags_ |= kGletFlagG0; 95 | } 96 | 97 | bool IsG0() { 98 | return (flags_ & kGletFlagG0) != 0; 99 | } 100 | 101 | Timer* GetTimer(); 102 | 103 | static Greenlet* Create(GreenletFunc entry, 104 | std::function* closure, 105 | bool sysg0 = false, 106 | intptr_t args = 0, 107 | bool joinable = false, 108 | int stack_size = kDefaultStackSize, 109 | const char* name = "greenlet"); 110 | 111 | private: 112 | static void StaticProc(intptr_t args); 113 | void Proc(); 114 | 115 | private: 116 | GUintptr schedlink_; 117 | tin::runtime::M* m_; 118 | tin::runtime::M* lockedm_; 119 | std::function cb_; 120 | GreenletFunc entry_; 121 | std::function closure_; 122 | intptr_t args_; 123 | void* retval_; 124 | char name_[32]; 125 | std::unique_ptr stack_; 126 | zcontext_t context_; 127 | int state_; 128 | int32_t flags_; 129 | int error_code_; 130 | Timer* timer_; 131 | }; 132 | 133 | void SpawnSimple(GreenletFunc entry, void* args = NULL, 134 | const char* name = NULL); 135 | void SpawnSimple(std::function closure, const char* name = NULL); 136 | 137 | } // namespace runtime 138 | 139 | void RuntimeSpawn(std::function* closure); 140 | 141 | } // namespace tin 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /tin/runtime/guintptr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | #include "cliff/build/build_config.h" 9 | #include "tin/runtime/util.h" 10 | 11 | namespace tin::runtime { 12 | 13 | // note, GUintptr is POD type, memset on GUintptr should be OK. 14 | class ALIGNAS(SIZE_OF_POINTER) GUintptr { 15 | public: 16 | GUintptr() 17 | : integer_(0) { 18 | } 19 | 20 | GUintptr(G* pointer) 21 | : integer_(reinterpret_cast(pointer)) { 22 | } 23 | 24 | GUintptr(void* pointer) 25 | : integer_(reinterpret_cast(pointer)) { 26 | } 27 | 28 | GUintptr(uintptr_t ingeter) 29 | : integer_(ingeter) { 30 | } 31 | 32 | GUintptr& operator=(GUintptr rhs) { 33 | integer_ = rhs.integer_; 34 | return *this; 35 | } 36 | 37 | GUintptr& operator=(uintptr_t rhs) { 38 | integer_ = rhs; 39 | return *this; 40 | } 41 | 42 | GUintptr& operator=(G* pointer) { 43 | integer_ = reinterpret_cast(pointer); 44 | return *this; 45 | } 46 | 47 | GUintptr& operator=(void* pointer) { 48 | integer_ = reinterpret_cast(pointer); 49 | return *this; 50 | } 51 | 52 | uintptr_t Integer() const { 53 | return integer_; 54 | } 55 | 56 | G* Pointer() const { 57 | return reinterpret_cast(integer_); 58 | } 59 | 60 | uintptr_t* Address() { 61 | return &integer_; 62 | } 63 | 64 | bool IsNull() { 65 | return integer_ == 0; 66 | } 67 | 68 | private: 69 | uintptr_t integer_; 70 | }; 71 | 72 | 73 | } // namespace tin::runtime 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /tin/runtime/m.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include "context/zcontext.h" 10 | #include "tin/sync/atomic.h" 11 | #include "tin/config/config.h" 12 | #include "tin/runtime/util.h" 13 | #include "tin/runtime/runtime.h" 14 | #include "tin/runtime/greenlet.h" 15 | #include "tin/runtime/p.h" 16 | #include "tin/runtime/scheduler.h" 17 | 18 | #include "tin/runtime/m.h" 19 | 20 | namespace tin { 21 | namespace runtime { 22 | 23 | M::M() 24 | : next_waitm_(0) 25 | , cache_() 26 | , wait_sema_() 27 | , park_() 28 | , p_(0) 29 | , spinning_(false) 30 | , schedlink_(0) 31 | , nextp_(NULL) 32 | , curg_(NULL) 33 | , g0_(0) 34 | , locked_g_(NULL) 35 | , mstart_fn_() 36 | , sys_context_(NULL) 37 | , unlock_info_(new UnLockInfo) 38 | , is_m0_(0) 39 | , dead_queue_() 40 | , locked_(0) { 41 | } 42 | 43 | M::~M() { 44 | delete g0_; 45 | } 46 | 47 | void M::EnsureSemaphoreExists() { 48 | if (!wait_sema_) { 49 | wait_sema_.reset(new absl::Notification(false)); 50 | } 51 | } 52 | 53 | void* M::G0StaticProc(intptr_t args) { 54 | M* m = reinterpret_cast(args); 55 | return m->G0Proc(); 56 | } 57 | 58 | void* M::G0Proc() { 59 | if (mstart_fn_) 60 | mstart_fn_(); 61 | if (nextp_ != NULL && !IsM0()) { 62 | AcquireP(nextp_); 63 | nextp_ = NULL; 64 | sched->G0Loop(); 65 | } 66 | jump_zcontext(g0_->MutableContext(), sys_context_, 0); 67 | return NULL; 68 | } 69 | 70 | M* M::Allocate(tin::runtime::P* p) { 71 | M* m = new M; 72 | if (reinterpret_cast(m) % 2 != 0) { 73 | LOG(FATAL) << "m's address is not power of 2"; 74 | } 75 | return m; 76 | } 77 | 78 | void M::OnSysThreadStart() { 79 | } 80 | 81 | void M::OnSysThreadStop() { 82 | srand(static_cast(time(NULL))); 83 | } 84 | 85 | void M::ThreadMain() { 86 | OnSysThreadStart(); 87 | 88 | g0_ = Greenlet::Create(G0StaticProc, 89 | NULL, 90 | true, 91 | reinterpret_cast(this), 92 | false, 93 | rtm_conf->StackSize(), 94 | "sysg0"); 95 | g0_->SetM(this); 96 | glet_tls = g0_; 97 | // switch to g0 98 | jump_zcontext(&sys_context_, 99 | *g0_->MutableContext(), 100 | reinterpret_cast(g0_)); 101 | // switch back from g0. 102 | OnSysThreadStop(); 103 | } 104 | 105 | void mspinning() { 106 | // startm's caller incremented nmspinning. Set the new M's spinning. 107 | GetM()->SetSpinning(true); 108 | } 109 | 110 | M* M::New(std::function fn, tin::runtime::P* p) { 111 | M* m = Allocate(p); 112 | m->nextp_ = p; 113 | std::swap(m->mstart_fn_, fn); 114 | std::thread t(&M::ThreadMain, m); 115 | m->sys_thread_handle_ = std::move(t); 116 | return m; 117 | } 118 | 119 | void M::Join() { 120 | if (sys_thread_handle_.joinable()) { 121 | sys_thread_handle_.join(); 122 | } 123 | } 124 | 125 | void M::Start(tin::runtime::P* p, bool spinning) { 126 | M* m = NULL; 127 | { 128 | SchedulerLocker guard; 129 | sched->MGetForP(p, spinning, &p, &m); 130 | } 131 | 132 | if (p == NULL) 133 | return; 134 | 135 | if (m == NULL) { 136 | std::function closure; 137 | if (spinning) { 138 | // closure = base::Bind(&mspinning); 139 | closure = absl::bind_front(&mspinning); 140 | } 141 | M::New(closure, p); 142 | return; 143 | } 144 | if (m->GetSpinning()) { 145 | LOG(FATAL) << "StartM: m is spinning"; 146 | } 147 | if (m->nextp_ != NULL) { 148 | LOG(FATAL) << "startm: m has p"; 149 | } 150 | if (spinning && !p->RunqEmpty()) { 151 | LOG(FATAL) << "startm: p has runnable gs"; 152 | } 153 | 154 | m->SetSpinning(spinning); 155 | m->nextp_ = p; 156 | m->park_.Wakeup(); 157 | } 158 | 159 | void M::StartLocked(G* gp) { 160 | G* curg = GetG(); 161 | M* mlocked = gp->LockedM(); 162 | if (mlocked == curg->M()) { 163 | LOG(FATAL) << "M::StartLocked: locked to me"; 164 | } 165 | if (mlocked->nextp_ != 0) { 166 | LOG(FATAL) << "M::StartLocked: m has p"; 167 | } 168 | AliasP* p = ReleaseP(); 169 | mlocked->nextp_ = p; 170 | mlocked->park_.Wakeup(); 171 | 172 | M::Stop(); 173 | } 174 | 175 | void M::Stop() { 176 | G* gp = GetG(); 177 | M* m = gp->M(); 178 | 179 | if (m->P() != NULL) { 180 | LOG(FATAL) << "Stop m holding p"; 181 | } 182 | if (m->GetSpinning()) { 183 | LOG(FATAL) << "Stop m spinning"; 184 | } 185 | { 186 | SchedulerLocker guard; 187 | if (rtm_env->ExitFlag()) { 188 | return; 189 | } 190 | sched->MPut(m); 191 | } 192 | m->park_.Sleep(); 193 | m->park_.Clear(); 194 | AcquireP(m->nextp_); 195 | m->nextp_ = NULL; 196 | } 197 | 198 | void M::StopLocked() { 199 | G* curg = GetG(); 200 | M* curm = curg->M(); 201 | if (curm->LockedG() == NULL || curm->LockedG()->M() != curm) { 202 | LOG(FATAL) << "M::StopLocked: inconsistent locking"; 203 | } 204 | 205 | if (curm->P() != NULL) { 206 | sched->HandoffP(ReleaseP()); 207 | } 208 | 209 | curm->park_.Sleep(); 210 | curm->park_.Clear(); 211 | AcquireP(curm->nextp_); 212 | curm->nextp_ = NULL; 213 | } 214 | 215 | void M::ClearDeadQueue() { 216 | if (!dead_queue_.empty()) { 217 | G* gp = dead_queue_.front(); 218 | delete gp; 219 | dead_queue_.pop_front(); 220 | } 221 | } 222 | 223 | // ----------------------------------------------------- 224 | 225 | 226 | } // namespace runtime 227 | } // namespace tin 228 | -------------------------------------------------------------------------------- /tin/runtime/m.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "context/zcontext.h" 14 | 15 | #include "tin/runtime/raw_mutex.h" 16 | #include "tin/runtime/unlock.h" 17 | 18 | namespace tin::runtime { 19 | 20 | class P; 21 | 22 | typedef class M AliasM; 23 | 24 | class M { 25 | public: 26 | M(const M&) = delete; 27 | M& operator=(const M&) = delete; 28 | virtual ~M(); 29 | 30 | bool GetSpinning() const { 31 | return spinning_; 32 | } 33 | 34 | void SetSpinning(bool spinning) { 35 | spinning_ = spinning; 36 | } 37 | 38 | void EnsureSemaphoreExists(); 39 | 40 | void SetNextWaitM(uintptr_t m) { 41 | next_waitm_ = m; 42 | } 43 | 44 | uintptr_t NextWaitM() { 45 | return next_waitm_; 46 | } 47 | 48 | absl::Notification* WaitSemaphore() { 49 | return wait_sema_.get(); 50 | } 51 | 52 | tin::runtime::P* P() { 53 | return p_; 54 | } 55 | 56 | void SetP(tin::runtime::P* p) { 57 | p_ = p; 58 | } 59 | 60 | void SetSchedLink(M* m) { 61 | schedlink_ = m; 62 | } 63 | 64 | M* GetSchedLink() const { 65 | return schedlink_; 66 | } 67 | 68 | G* CurG() const { 69 | return curg_; 70 | } 71 | 72 | G* G0() const { 73 | return g0_; 74 | } 75 | 76 | G* LockedG() const { 77 | return locked_g_; 78 | } 79 | 80 | void SetLockedG(G* gp) { 81 | locked_g_ = gp; 82 | } 83 | 84 | void SetCurG(G* gp) { 85 | curg_ = gp; 86 | } 87 | 88 | 89 | void SetUnlockInfo(UnlockFunc f, void* arg1, void* arg2, G* owner) { 90 | unlock_info_->SetF(f); 91 | unlock_info_->SetArg1(arg1); 92 | unlock_info_->SetArg2(arg2); 93 | unlock_info_->SetOwner(owner); 94 | } 95 | 96 | UnLockInfo* GetUnlockInfo() const { 97 | return unlock_info_.get(); 98 | } 99 | 100 | static M* New(std::function fn, tin::runtime::P* p); 101 | 102 | static void Start(tin::runtime::P* p, bool spinning); 103 | 104 | static void StartLocked(G* gp); 105 | 106 | static void Stop(); 107 | 108 | static void StopLocked(); 109 | 110 | void Join(); 111 | 112 | void SetM0Flag() { 113 | is_m0_ = true; 114 | } 115 | 116 | bool IsM0() const { 117 | return is_m0_; 118 | } 119 | 120 | void ClearDeadQueue(); 121 | 122 | void AddToDeadQueue(G* gp) { 123 | dead_queue_.push_back(gp); 124 | } 125 | 126 | uint32_t* MutableLocked() { 127 | return &locked_; 128 | } 129 | 130 | char* Cache() { 131 | if (!cache_) { 132 | cache_.reset(new char[64 * 1024]); 133 | } 134 | return cache_.get(); 135 | } 136 | 137 | private: 138 | // private constructor 139 | M(); 140 | 141 | void OnSysThreadStart(); 142 | virtual void ThreadMain(); 143 | void OnSysThreadStop(); 144 | 145 | static void* G0StaticProc(intptr_t args); 146 | void* G0Proc(); 147 | 148 | static M* Allocate(tin::runtime::P* p); 149 | void DoUnlock(); 150 | 151 | private: 152 | uintptr_t next_waitm_; 153 | std::unique_ptr cache_; 154 | std::unique_ptr wait_sema_; 155 | Note park_; 156 | tin::runtime::P* p_; 157 | bool spinning_; 158 | tin::runtime::M* schedlink_; 159 | tin::runtime::P* nextp_; 160 | G* curg_; 161 | G* g0_; 162 | G* locked_g_; 163 | std::function mstart_fn_; 164 | zcontext_t sys_context_; 165 | std::thread sys_thread_handle_; 166 | std::unique_ptr unlock_info_; 167 | bool is_m0_; 168 | std::list dead_queue_; 169 | uint32_t locked_; 170 | }; 171 | 172 | } // namespace tin::runtime 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /tin/runtime/net/netpoll.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include "tin/sync/atomic.h" 8 | #include "tin/runtime/runtime.h" 9 | #include "tin/runtime/greenlet.h" 10 | #include "tin/runtime/scheduler.h" 11 | #include "tin/runtime/net/netpoll.h" 12 | 13 | namespace tin { 14 | namespace runtime { 15 | 16 | namespace { 17 | uint32_t net_poll_Inited = 0; 18 | } 19 | 20 | bool NetPollInited() { 21 | return atomic::acquire_load32(&net_poll_Inited) != 0; 22 | } 23 | 24 | void NetPollPostInit() { 25 | atomic::store32(&net_poll_Inited, 1); 26 | } 27 | 28 | void NetPollDeinit() { 29 | NetPollPreDeinit(); 30 | atomic::store32(&net_poll_Inited, 0); 31 | } 32 | 33 | void NetPollReady(G** gpp, PollDescriptor* pd, int32_t mode) { 34 | G* rg = 0; 35 | G* wg = 0; 36 | 37 | if (mode == 'r' || mode == 'r' + 'w') { 38 | rg = NetPollUnblock(pd, 'r', true); 39 | } 40 | if (mode == 'w' || mode == 'r' + 'w') { 41 | wg = NetPollUnblock(pd, 'w', true); 42 | } 43 | 44 | if (rg != NULL) { 45 | rg->SetSchedLink(*gpp); 46 | *gpp = rg; 47 | } 48 | if (wg != NULL) { 49 | wg->SetSchedLink(*gpp); 50 | *gpp = wg; 51 | } 52 | } 53 | 54 | int NetPollCheckErr(PollDescriptor* pd, int32_t mode) { 55 | if (pd->closing) { 56 | return 1; // errClosing 57 | } 58 | if ((mode == 'r' && pd->rd < 0) || (mode == 'w' && pd->wd < 0)) { 59 | return 2; // errTimeout 60 | } 61 | return 0; 62 | } 63 | 64 | bool NetPollBlockCommit(void* arg1, void* arg2) { 65 | uintptr_t gp = reinterpret_cast(arg1); 66 | uintptr_t* gpp = reinterpret_cast(arg2); 67 | return atomic::release_cas(gpp, kPdWait, gp); 68 | } 69 | 70 | bool NetPollBlock(PollDescriptor* pd, int32_t mode, bool waitio) { 71 | uintptr_t* gpp = &pd->rg; 72 | if (mode == 'w') { 73 | gpp = &pd->wg; 74 | } 75 | 76 | while (true) { 77 | uintptr_t old = *gpp; 78 | if (old == kPdReady) { 79 | *gpp = 0; 80 | return true; 81 | } 82 | if (old != 0) { 83 | LOG(FATAL) << "NetPollBlock: double wait"; 84 | } 85 | if (atomic::release_cas(gpp, 0, kPdWait)) { 86 | break; 87 | } 88 | } 89 | 90 | if (waitio || NetPollCheckErr(pd, mode) == 0) { 91 | G* gp = GetG(); 92 | Park(NetPollBlockCommit, gp, gpp); 93 | } 94 | 95 | uintptr_t old = atomic::exchange(gpp, 0); 96 | if (old > kPdWait) { 97 | LOG(FATAL) << "NetPollBlock: corrupted state"; 98 | } 99 | return old == kPdReady; 100 | } 101 | 102 | G* NetPollUnblock(PollDescriptor* pd, int32_t mode, bool ioready) { 103 | uintptr_t* gpp = &pd->rg; 104 | if (mode == 'w') { 105 | gpp = &pd->wg; 106 | } 107 | 108 | while (true) { 109 | uintptr_t old = *gpp; 110 | if (old == kPdReady) { 111 | return NULL; 112 | } 113 | if (old == 0 && !ioready) { 114 | // Only set READY for ioready. runtime_pollWait 115 | // will check for timeout/cancel before waiting. 116 | return NULL; 117 | } 118 | uintptr_t new_value = 0; 119 | if (ioready) { 120 | new_value = kPdReady; 121 | } 122 | 123 | if (atomic::release_cas(gpp, old, new_value)) { 124 | if (old == kPdReady || old == kPdWait) { 125 | old = 0; 126 | } 127 | return GpCastBack(old); 128 | } 129 | } 130 | } 131 | 132 | void NetPollDeadlineImpl(PollDescriptor* pd, uintptr_t seq, bool read, 133 | bool write) { 134 | pd->lock.Lock(); 135 | if (seq != pd->seq) { 136 | pd->lock.Unlock(); 137 | pd->Release(); 138 | return; 139 | } 140 | G* rg = NULL; 141 | if (read) { 142 | if (pd->rd <= 0 || pd->rt.f == NULL) { 143 | LOG(FATAL) << "NetPollDeadlineImpl: inconsistent read deadline"; 144 | } 145 | pd->rd = -1; 146 | // full memory barrier between store to rd and load of rg in NetPollUnblock 147 | atomic::store(reinterpret_cast(&pd->rt.f), 0); 148 | rg = NetPollUnblock(pd, 'r', false); 149 | } 150 | 151 | G* wg = NULL; 152 | if (write) { 153 | if ((pd->wd <= 0 || pd->wt.f == NULL) && !read) { 154 | LOG(FATAL) << "NetPollDeadlineImpl: inconsistent write deadline"; 155 | } 156 | pd->wd = -1; 157 | // full memory barrier between store to rd and load of wg in NetPollUnblock 158 | atomic::store(reinterpret_cast(&pd->wt.f), 0); 159 | wg = NetPollUnblock(pd, 'w', false); 160 | } 161 | pd->lock.Unlock(); 162 | if (rg != NULL) { 163 | Ready(rg); 164 | } 165 | if (wg != NULL) { 166 | Ready(wg); 167 | } 168 | pd->Release(); 169 | } 170 | 171 | void NetpollDeadline(void* arg, uintptr_t seq) { 172 | NetPollDeadlineImpl(static_cast(arg), seq, true, true); 173 | } 174 | 175 | void NetpollReadDeadline(void* arg, uintptr_t seq) { 176 | NetPollDeadlineImpl(static_cast(arg), seq, true, false); 177 | } 178 | 179 | void NetPollWriteDeadline(void* arg, uintptr_t seq) { 180 | NetPollDeadlineImpl(static_cast(arg), seq, false, true); 181 | } 182 | 183 | } // namespace runtime 184 | } // namespace tin 185 | -------------------------------------------------------------------------------- /tin/runtime/net/netpoll.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include "tin/runtime/net/poll_descriptor.h" 10 | 11 | namespace tin { 12 | namespace runtime { 13 | 14 | const uintptr_t kPdReady = 1; 15 | const uintptr_t kPdWait = 2; 16 | 17 | void NetPollInit(); 18 | 19 | bool NetPollInited(); 20 | 21 | void NetPollPostInit(); 22 | 23 | void NetPollShutdown(); 24 | 25 | void NetPollPreDeinit(); 26 | 27 | void NetPollDeinit(); 28 | 29 | int32_t NetPollOpen(uintptr_t fd, PollDescriptor* pd); 30 | 31 | int32_t NetPollClose(uintptr_t fd); 32 | 33 | void NetPollArm(PollDescriptor* pd, int mode); 34 | 35 | G* NetPoll(bool block); 36 | 37 | int NetPollCheckErr(PollDescriptor* pd, int32_t mode); 38 | 39 | bool NetPollBlock(PollDescriptor* pd, int32_t mode, bool waitio); 40 | 41 | G* NetPollUnblock(PollDescriptor* pd, int32_t mode, bool ioready); 42 | 43 | void NetPollReady(G** gpp, PollDescriptor* pd, int32_t mode); 44 | 45 | void NetpollDeadline(void* arg, uintptr_t seq); 46 | 47 | void NetpollReadDeadline(void* arg, uintptr_t seq); 48 | 49 | void NetPollWriteDeadline(void* arg, uintptr_t seq); 50 | 51 | } // namespace runtime 52 | } // namespace tin 53 | -------------------------------------------------------------------------------- /tin/runtime/net/netpoll_epoll.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include "tin/runtime/runtime.h" 8 | #include "tin/runtime/posix_util.h" 9 | #include "tin/runtime/net/netpoll.h" 10 | 11 | namespace { 12 | int epfd = -1; 13 | } 14 | 15 | namespace tin { 16 | namespace runtime { 17 | 18 | struct PollDescriptor; 19 | 20 | void NetPollInit() { 21 | epfd = epoll_create(1024); 22 | DCHECK_NE(epfd, -1); 23 | if (epfd >= 0) { 24 | DCHECK_EQ(tin::Cloexec(epfd, true), 0); 25 | return; 26 | } 27 | LOG(FATAL) << "epoll_create failed"; 28 | } 29 | 30 | void NetPollShutdown() { 31 | } 32 | 33 | void NetPollPreDeinit() { 34 | } 35 | 36 | #ifndef EPOLLRDHUP 37 | #define EPOLLRDHUP 0x2000 38 | #endif 39 | 40 | int32_t NetPollOpen(uintptr_t fd, PollDescriptor* pd) { 41 | struct epoll_event ev; 42 | ev.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET; 43 | ev.data.ptr = pd; 44 | if (epoll_ctl(epfd, EPOLL_CTL_ADD, static_cast(fd), &ev) == -1) 45 | return errno; 46 | return 0; 47 | } 48 | 49 | int32_t NetPollClose(uintptr_t fd) { 50 | struct epoll_event ev; 51 | if (epoll_ctl(epfd, EPOLL_CTL_DEL, static_cast(fd), &ev) == -1) 52 | return errno; 53 | return 0; 54 | } 55 | 56 | void NetPollArm(PollDescriptor* pd, int mode) { 57 | LOG(FATAL) << "unused"; 58 | } 59 | 60 | G* NetPoll(bool block) { 61 | if (epfd == -1) 62 | return NULL; 63 | int waitms = -1; 64 | epoll_event events[128]; // 1536 bytes on stack. 65 | while (true) { 66 | int n = 67 | HANDLE_EINTR(epoll_wait(epfd, &events[0], arraysize(events), waitms)); 68 | if (n < 0) { 69 | LOG(FATAL) << "epoll_wait, fatal error, error code: " << errno; 70 | } 71 | G* gp = NULL; 72 | for (int i = 0; i < n; ++i) { 73 | epoll_event& ev = events[i]; 74 | if (ev.events == 0) { 75 | continue; 76 | } 77 | int mode = 0; 78 | if ((ev.events & (EPOLLIN | EPOLLRDHUP | EPOLLHUP | EPOLLERR)) != 0) { 79 | mode += 'r'; 80 | } 81 | if ((ev.events & (EPOLLOUT | EPOLLHUP | EPOLLERR)) != 0) { 82 | mode += 'w'; 83 | } 84 | if (mode != 0) { 85 | PollDescriptor* pd = static_cast(ev.data.ptr); 86 | NetPollReady(&gp, pd, mode); 87 | } 88 | } 89 | if (!block || gp != NULL) { 90 | return gp; 91 | } 92 | } 93 | } 94 | 95 | } // namespace runtime 96 | } // namespace tin 97 | -------------------------------------------------------------------------------- /tin/runtime/net/netpoll_kqueue.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | #include "tin/runtime/runtime.h" 20 | #include "tin/runtime/posix_util.h" 21 | #include "tin/runtime/net/NetPoll.h" 22 | 23 | namespace { 24 | int kq = -1; 25 | } 26 | 27 | namespace tin { 28 | namespace runtime { 29 | 30 | struct PollDescriptor; 31 | 32 | void NetPollInit() { 33 | kq = kqueue(); 34 | DCHECK_NE(kq, -1); 35 | if (kq >= 0) { 36 | DCHECK_EQ(tin::Cloexec(kq, true), 0); 37 | return; 38 | } 39 | LOG(FATAL) << "kqueue failed"; 40 | } 41 | 42 | void NetPollShutdown() { 43 | } 44 | 45 | void NetPollPreDeinit() { 46 | } 47 | 48 | int32_t NetPollOpen(uintptr_t fd, PollDescriptor* pd) { 49 | struct kevent ev[2]; 50 | ev[0].ident = fd; 51 | ev[0].filter = EVFILT_READ; 52 | ev[0].flags = EV_ADD | EV_CLEAR; 53 | ev[0].fflags = 0; 54 | ev[0].data = 0; 55 | ev[0].udata = pd; 56 | ev[1] = ev[0]; 57 | ev[1].filter = EVFILT_WRITE; 58 | int n = kevent(kq, &ev[0], 2, NULL, 0, NULL); 59 | return n == -1 ? errno : 0; 60 | } 61 | 62 | int32_t NetPollClose(uintptr_t fd) { 63 | (void)fd; 64 | // Don't need to unregister because calling close() 65 | // on fd will remove any kevents that reference the descriptor. 66 | return 0; 67 | } 68 | 69 | void NetPollArm(PollDescriptor* pd, int mode) { 70 | LOG(FATAL) << "unused"; 71 | } 72 | 73 | G* NetPoll(bool block) { 74 | if (kq == -1) { 75 | return NULL; 76 | } 77 | struct timespec* tp = NULL; 78 | struct timespec ts; 79 | memset(&ts, 0, sizeof(ts)); 80 | if (!block) { 81 | tp = &ts; 82 | } 83 | struct kevent events[64]; 84 | while (true) { 85 | int n = 86 | HANDLE_EINTR(kevent(kq, NULL, 0, &events[0], arraysize(events), tp)); 87 | if (n == -1) { 88 | LOG(FATAL) << "kevent failed"; 89 | } 90 | 91 | G* gp = NULL; 92 | for (int i = 0; i < n; ++i) { 93 | struct kevent& ev = events[i]; 94 | int mode = 0; 95 | if (ev.filter == EVFILT_READ) { 96 | mode += 'r'; 97 | } 98 | if (ev.filter == EVFILT_WRITE) { 99 | mode += 'w'; 100 | } 101 | if (mode != 0) { 102 | PollDescriptor* pd = static_cast(ev.udata); 103 | NetPollReady(&gp, pd, mode); 104 | } 105 | } 106 | if (!block || gp != NULL) { 107 | return gp; 108 | } 109 | } 110 | return NULL; 111 | } 112 | 113 | } // namespace runtime 114 | } // namespace tin 115 | -------------------------------------------------------------------------------- /tin/runtime/net/netpoll_windows.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "tin/platform/platform_win.h" 11 | #include "tin/runtime/runtime.h" 12 | 13 | #include "tin/runtime/net/NetPoll.h" 14 | 15 | 16 | namespace tin { 17 | namespace runtime { 18 | 19 | struct PollDescriptor; 20 | 21 | struct NetOP { 22 | // used by windows 23 | OVERLAPPED ol; 24 | // used by NetPoll 25 | PollDescriptor* pd; 26 | int32_t mode; 27 | int32_t eno; 28 | uint32_t qty; 29 | }; 30 | 31 | struct overlappedEntry { 32 | uintptr_t key; 33 | NetOP* op; 34 | uintptr_t internal; 35 | uint32_t qty; 36 | }; 37 | 38 | HANDLE iocphandle = INVALID_HANDLE_VALUE; 39 | 40 | void NetPollInit() { 41 | iocphandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0xFFFFFFFF); 42 | if (iocphandle == 0) { 43 | LOG(FATAL) << "NetPoll: failed to create iocp handle"; 44 | } 45 | } 46 | 47 | void NetPollShutdown() { 48 | if (!NetPollInited()) 49 | return; 50 | PostQueuedCompletionStatus(iocphandle, 0, NULL, NULL); 51 | } 52 | 53 | void NetPollPreDeinit() { 54 | CloseHandle(iocphandle); 55 | iocphandle = INVALID_HANDLE_VALUE; 56 | } 57 | 58 | int32_t NetPollOpen(uintptr_t fd, PollDescriptor* pd) { 59 | if (CreateIoCompletionPort((HANDLE)fd, iocphandle, 0, 0) == 0) { 60 | return static_cast(GetLastError()); 61 | } 62 | return 0; 63 | } 64 | 65 | int32_t NetPollClose(uintptr_t fd) { 66 | // nothing to do 67 | return 0; 68 | } 69 | 70 | void NetPollArm(PollDescriptor* pd, int mode) { 71 | LOG(FATAL) << "unused"; 72 | } 73 | 74 | void handlecompletion(G** gpp, NetOP* op, DWORD error_no, uint32_t qty) { 75 | if (op == NULL) { 76 | LOG(FATAL) << "NetPoll: GetQueuedCompletionStatus returned op == nil"; 77 | } 78 | int32_t mode = op->mode; 79 | if (mode != 'r' && mode != 'w') { 80 | LOG(FATAL) << "NetPoll: GetQueuedCompletionStatus returned invalid mode"; 81 | } 82 | op->eno = error_no; 83 | op->qty = qty; 84 | NetPollReady(gpp, op->pd, mode); 85 | } 86 | 87 | G* NetPoll(bool block) { 88 | overlappedEntry entries[64]; 89 | DWORD qty, flags, i; 90 | ULONG_PTR key = 0; 91 | ULONG n; 92 | DWORD error_no; 93 | NetOP* op; 94 | G* gp = NULL; 95 | DWORD wait = 0; 96 | if (block) { 97 | wait = INFINITE; 98 | } 99 | 100 | bool shutdown_flag = false; 101 | 102 | if (pGetQueuedCompletionStatusEx != NULL) { 103 | n = 64; 104 | 105 | if (pGetQueuedCompletionStatusEx(iocphandle, 106 | (LPOVERLAPPED_ENTRY)&entries[0], 107 | n, &n, wait, 0) == 0) { 108 | error_no = GetLastError(); 109 | if (!block && error_no == WAIT_TIMEOUT) { 110 | return NULL; 111 | } 112 | LOG(INFO) << "NetPoll: GetQueuedCompletionStatusEx failed"; 113 | return NULL; 114 | } 115 | for (i = 0; i < n; i++) { 116 | op = entries[i].op; 117 | error_no = 0; 118 | qty = 0; 119 | if (op != NULL) { 120 | if (WSAGetOverlappedResult(op->pd->fd, 121 | (LPWSAOVERLAPPED)op, 122 | (LPDWORD)&qty, 123 | 0, 124 | (LPDWORD)&flags) == 0) { 125 | error_no = GetLastError(); 126 | } 127 | handlecompletion(&gp, op, error_no, qty); 128 | } else { 129 | shutdown_flag = true; 130 | } 131 | } 132 | } else { 133 | op = NULL; 134 | error_no = 0; 135 | qty = 0; 136 | if (GetQueuedCompletionStatus(iocphandle, 137 | &qty, 138 | &key, 139 | reinterpret_cast(&op), 140 | wait) == 0) { 141 | error_no = GetLastError(); 142 | if (!block && error_no == WAIT_TIMEOUT) { 143 | return NULL; 144 | } 145 | if (op == NULL) { 146 | LOG(INFO) << "NetPoll: GetQueuedCompletionStatus failed"; 147 | return NULL; 148 | } 149 | } 150 | if (op != NULL) { 151 | handlecompletion(&gp, op, error_no, qty); 152 | } else { 153 | shutdown_flag = true; 154 | } 155 | } 156 | 157 | if (shutdown_flag) { 158 | PostQueuedCompletionStatus(iocphandle, 0, NULL, NULL); 159 | } 160 | return gp; 161 | } 162 | 163 | } // namespace runtime 164 | } // namespace tin 165 | -------------------------------------------------------------------------------- /tin/runtime/net/poll_descriptor.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "tin/runtime/net/poll_descriptor.h" 6 | 7 | namespace tin { 8 | namespace runtime { 9 | 10 | PollDescriptor::PollDescriptor() { 11 | fd = 0; 12 | closing = false; 13 | seq = 0; 14 | rg = 0; 15 | rd = 0; 16 | wg = 0; 17 | wd = 0; 18 | user = 0; 19 | } 20 | 21 | } // namespace runtime 22 | } // namespace tin 23 | -------------------------------------------------------------------------------- /tin/runtime/net/poll_descriptor.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include "tin/runtime/raw_mutex.h" 10 | #include "tin/runtime/timer/timer_queue.h" 11 | #include 12 | 13 | 14 | namespace tin::runtime { 15 | 16 | 17 | struct PollDescriptor : public cliff::RefCountedThreadSafe { 18 | PollDescriptor(); 19 | PollDescriptor(const PollDescriptor&) = delete; 20 | PollDescriptor& operator=(const PollDescriptor&) = delete; 21 | 22 | ~PollDescriptor() { 23 | // LOG(INFO) << "PollDescriptor destructor"; 24 | } 25 | RawMutex lock; 26 | uintptr_t fd; 27 | bool closing; 28 | uintptr_t seq; 29 | 30 | uintptr_t rg; 31 | Timer rt; 32 | int64_t rd; 33 | 34 | uintptr_t wg; 35 | Timer wt; 36 | int64_t wd; 37 | 38 | uint32_t user; 39 | 40 | }; 41 | 42 | inline PollDescriptor* NewPollDescriptor() { 43 | PollDescriptor* descriptor = new PollDescriptor; 44 | descriptor->AddRef(); 45 | return descriptor; 46 | } 47 | 48 | } // namespace tin::runtime 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /tin/runtime/net/pollops.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | 8 | #include "tin/sync/atomic.h" 9 | #include "tin/runtime/runtime.h" 10 | #include "tin/runtime/scheduler.h" 11 | #include "tin/runtime/net/netpoll.h" 12 | #include "tin/runtime/net/pollops.h" 13 | 14 | namespace tin { 15 | namespace runtime { 16 | namespace pollops { 17 | 18 | void ServerInit() { 19 | NetPollInit(); 20 | NetPollPostInit(); 21 | } 22 | 23 | void ServerNotifyShutdown() { 24 | NetPollShutdown(); 25 | } 26 | 27 | void ServerDeinit() { 28 | NetPollDeinit(); 29 | } 30 | 31 | PollDescriptor* Open(uintptr_t fd, int* error_no) { 32 | PollDescriptor* pd = NewPollDescriptor(); 33 | pd->lock.Lock(); 34 | if (pd->wg != 0 && pd->wg != kPdReady) { 35 | LOG(FATAL) << "netpollOpen: blocked write on free descriptor"; 36 | } 37 | if (pd->rg != 0 && pd->rg != kPdReady) { 38 | LOG(FATAL) << "netpollOpen: blocked read on free descriptor"; 39 | } 40 | pd->fd = fd; 41 | pd->closing = false; 42 | pd->seq++; 43 | pd->rg = 0; 44 | pd->rd = 0; 45 | pd->wg = 0; 46 | pd->wd = 0; 47 | pd->lock.Unlock(); 48 | 49 | *error_no = NetPollOpen(fd, pd); 50 | return pd; 51 | } 52 | 53 | void Close(PollDescriptor* pd) { 54 | if (!pd->closing) { 55 | LOG(FATAL) << "netpollClose: close w/o unblock"; 56 | } 57 | 58 | if (pd->wg != 0 && pd->wg != kPdReady) { 59 | LOG(FATAL) << "netpollOpen: blocked write on closing descriptor"; 60 | } 61 | if (pd->rg != 0 && pd->rg != kPdReady) { 62 | LOG(FATAL) << "netpollOpen: blocked read on closing descriptor"; 63 | } 64 | NetPollClose(pd->fd); 65 | pd->Release(); 66 | } 67 | 68 | int Reset(PollDescriptor* pd, int mode) { 69 | int err = NetPollCheckErr(pd, mode); 70 | if (err != 0) { 71 | return err; 72 | } 73 | if (mode == 'r') { 74 | pd->rg = 0; 75 | } else if (mode == 'w') { 76 | pd->wg = 0; 77 | } 78 | return 0; 79 | } 80 | 81 | int Wait(PollDescriptor* pd, int mode) { 82 | int err = NetPollCheckErr(pd, mode); 83 | if (err != 0) { 84 | return err; 85 | } 86 | 87 | while (!NetPollBlock(pd, mode, false)) { 88 | err = NetPollCheckErr(pd, mode); 89 | if (err != 0) { 90 | return err; 91 | } 92 | // Can happen if timeout has fired and unblocked us, 93 | // but before we had a chance to run, timeout has been reset. 94 | // Pretend it has not happened and retry. 95 | } 96 | return 0; 97 | } 98 | 99 | void WaitCanceled(PollDescriptor* pd, int mode) { 100 | while (!NetPollBlock(pd, mode, true)) { 101 | } 102 | } 103 | 104 | void AddTimerRefCounted(PollDescriptor* pd, Timer* t) { 105 | pd->AddRef(); 106 | timer_q->AddTimer(t); 107 | } 108 | 109 | void DelTimerRefCounted(PollDescriptor* pd, Timer* t) { 110 | if (timer_q->DelTimer(t)) 111 | pd->Release(); 112 | } 113 | 114 | void SetDeadline(PollDescriptor* pd, int64_t d, int mode) { 115 | pd->lock.Lock(); 116 | if (pd->closing) { 117 | pd->lock.Unlock(); 118 | return; 119 | } 120 | pd->seq++; // invalidate current timers 121 | // Reset current timers. 122 | if (pd->rt.f != NULL) { 123 | DelTimerRefCounted(pd, &pd->rt); 124 | pd->rt.f = NULL; 125 | } 126 | 127 | if (pd->wt.f != NULL) { 128 | DelTimerRefCounted(pd, &pd->wt); 129 | pd->wt.f = NULL; 130 | } 131 | 132 | if (d != 0 && d <= MonoNow()) { 133 | d = -1; 134 | } 135 | if (mode == 'r' || mode == 'r' + 'w') { 136 | pd->rd = d; 137 | } 138 | if (mode == 'w' || mode == 'r' + 'w') { 139 | pd->wd = d; 140 | } 141 | 142 | if (pd->rd > 0 && pd->rd == pd->wd) { 143 | pd->rt.f = NetpollDeadline; 144 | pd->rt.when = pd->rd; 145 | // Copy current seq into the timer arg. 146 | // Timer func will check the seq against current descriptor seq, 147 | // if they differ the descriptor was reused or timers were reset. 148 | pd->rt.arg = pd; 149 | pd->rt.seq = pd->seq; 150 | AddTimerRefCounted(pd, &pd->rt); 151 | } else { 152 | if (pd->rd > 0) { 153 | pd->rt.f = NetpollReadDeadline; 154 | pd->rt.when = pd->rd; 155 | pd->rt.arg = pd; 156 | pd->rt.seq = pd->seq; 157 | AddTimerRefCounted(pd, &pd->rt); 158 | } 159 | 160 | if (pd->wd > 0) { 161 | pd->wt.f = NetPollWriteDeadline; 162 | pd->wt.when = pd->wd; 163 | pd->wt.arg = pd; 164 | pd->wt.seq = pd->seq; 165 | AddTimerRefCounted(pd, &pd->wt); 166 | } 167 | } 168 | 169 | G* rg = NULL; 170 | G* wg = NULL; 171 | // full memory barrier between stores to rd/wd 172 | // and load of rg/wg in NetPollUnblock 173 | std::atomic_thread_fence(std::memory_order_seq_cst); 174 | if (pd->rd < 0) { 175 | rg = NetPollUnblock(pd, 'r', false); 176 | } 177 | if (pd->wd < 0) { 178 | wg = NetPollUnblock(pd, 'w', false); 179 | } 180 | pd->lock.Unlock(); 181 | 182 | if (rg != NULL) { 183 | Ready(rg); 184 | } 185 | if (wg != NULL) { 186 | Ready(wg); 187 | } 188 | } 189 | 190 | void Unblock(PollDescriptor* pd) { 191 | pd->lock.Lock(); 192 | if (pd->closing) { 193 | LOG(FATAL) << "netpollUnblock: already closing"; 194 | } 195 | pd->closing = true; 196 | pd->seq++; 197 | 198 | G* rg = NULL; 199 | G* wg = NULL; 200 | // full memory barrier between stores to rd/wd 201 | // and load of rg/wg in NetPollUnblock 202 | std::atomic_thread_fence(std::memory_order_seq_cst); 203 | 204 | rg = NetPollUnblock(pd, 'r', false); 205 | wg = NetPollUnblock(pd, 'w', false); 206 | if (pd->rt.f != NULL) { 207 | DelTimerRefCounted(pd, &pd->rt); 208 | pd->rt.f = NULL; 209 | } 210 | 211 | if (pd->wt.f != NULL) { 212 | DelTimerRefCounted(pd, &pd->wt); 213 | pd->wt.f = NULL; 214 | } 215 | pd->lock.Unlock(); 216 | 217 | if (rg != NULL) { 218 | Ready(rg); 219 | } 220 | if (wg != NULL) { 221 | Ready(wg); 222 | } 223 | } 224 | 225 | } // namespace pollops 226 | } // namespace runtime 227 | } // namespace tin 228 | -------------------------------------------------------------------------------- /tin/runtime/net/pollops.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | namespace tin { 8 | namespace runtime { 9 | struct PollDescriptor; 10 | 11 | namespace pollops { 12 | 13 | void ServerInit(); 14 | void ServerNotifyShutdown(); 15 | void ServerDeinit(); 16 | PollDescriptor* Open(uintptr_t fd, int* error_no); 17 | int Wait(PollDescriptor* pd, int mode); 18 | void Close(PollDescriptor* pd); 19 | int Reset(PollDescriptor* pd, int mode); 20 | void Unblock(PollDescriptor* pd); 21 | void WaitCanceled(PollDescriptor* pd, int mode); 22 | void SetDeadline(PollDescriptor* pd, int64_t d, int mode); 23 | 24 | } // namespace pollops 25 | } // namespace runtime 26 | } // namespace tin 27 | 28 | 29 | -------------------------------------------------------------------------------- /tin/runtime/os_posix.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include "cstdint" 7 | 8 | namespace tin { 9 | 10 | /* Available from 2.6.32 onwards. */ 11 | #ifndef CLOCK_MONOTONIC_COARSE 12 | # define CLOCK_MONOTONIC_COARSE 6 13 | #endif 14 | 15 | int64_t Now() { 16 | int64_t t = base::Time::Now().ToTimeT(); 17 | // to nano seconds. 18 | return t * 1000000000LL; 19 | } 20 | #if !defined(OS_MACOSX) 21 | int64_t MonoNow() { 22 | static clock_t fast_clock_id = -1; 23 | struct timespec t; 24 | // ignore data race currently, it's harmless. 25 | if (fast_clock_id == -1) { 26 | if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 && 27 | t.tv_nsec <= 1 * 1000 * 1000) { 28 | fast_clock_id = CLOCK_MONOTONIC_COARSE; 29 | } else { 30 | fast_clock_id = CLOCK_MONOTONIC; 31 | } 32 | } 33 | clock_t clock_id = fast_clock_id; 34 | if (clock_gettime(clock_id, &t)) 35 | return 0; /* Not really possible. */ 36 | 37 | return t.tv_sec * 1000000000LL + t.tv_nsec; 38 | } 39 | #else 40 | int64_t MonoNow() { 41 | int64_t t = base::TimeTicks::Now().ToInternalValue() * 1000; 42 | // to nano seconds. 43 | return t; 44 | } 45 | #endif 46 | 47 | int32_t NowSeconds() { 48 | int64_t millisecond = Now() / 1000000000LL; 49 | return static_cast(millisecond); 50 | } 51 | 52 | } // namespace tin 53 | -------------------------------------------------------------------------------- /tin/runtime/os_win.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | 8 | namespace tin { 9 | 10 | const uintptr_t kInterruptTime = 0x7ffe0008; 11 | const uintptr_t kSystemTime = 0x7ffe0014; 12 | 13 | struct KSYSTEMIME { 14 | uint32_t LowPart; 15 | int32_t High1Time; 16 | int32_t High2Time; 17 | }; 18 | 19 | int64_t SysTime(uintptr_t addr) { 20 | const KSYSTEMIME* time_addr = reinterpret_cast(addr); 21 | KSYSTEMIME t; 22 | int64_t time; 23 | while (true) { 24 | t.High1Time = time_addr->High1Time; 25 | t.LowPart = time_addr->LowPart; 26 | t.High2Time = time_addr->High2Time; 27 | if (t.High1Time == t.High2Time) { 28 | time = static_cast(t.High1Time) << 32 | 29 | static_cast(t.LowPart); 30 | break; 31 | } 32 | } 33 | return time; 34 | } 35 | 36 | 37 | int64_t Now() { 38 | return (SysTime(kSystemTime) - 116444736000000000) * 100; 39 | } 40 | 41 | int64_t MonoNow() { 42 | return SysTime(kInterruptTime) * 100; 43 | } 44 | 45 | int32_t NowSeconds() { 46 | int64_t millisecond = Now() / 1000000000; 47 | return static_cast(millisecond); 48 | } 49 | 50 | } // namespace tin 51 | -------------------------------------------------------------------------------- /tin/runtime/p.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include "tin/runtime/util.h" 8 | #include "tin/runtime/guintptr.h" 9 | 10 | namespace tin { 11 | namespace runtime { 12 | class M; 13 | 14 | // P status 15 | enum { 16 | kPidle = 0, 17 | kPrunning, // Only this P is allowed to change from _Prunning. 18 | kPsyscall, 19 | kPdead 20 | }; 21 | 22 | typedef class P AliasP; 23 | 24 | class P { 25 | public: 26 | explicit P(int id); 27 | P(const P&) = delete; 28 | P& operator=(const P&) = delete; 29 | int Id() const { 30 | return id_; 31 | } 32 | 33 | int32_t RunqCapacity() const { 34 | return kRunqCapacity; 35 | } 36 | 37 | bool RunqEmpty(); 38 | 39 | void RunqPut(G* gp, bool next); 40 | 41 | G* RunqGet(bool* inherit_time = NULL); 42 | 43 | G* RunqSteal(P* p2, bool steal_nextg); 44 | 45 | void MoveRunqToGlobal(); 46 | 47 | void SetLink(P* p) { 48 | link_ = p; 49 | } 50 | 51 | P* Link() { 52 | return link_; 53 | } 54 | 55 | uintptr_t Address() { 56 | return reinterpret_cast(this); 57 | } 58 | 59 | tin::runtime::M* M() const { 60 | return m_; 61 | } 62 | 63 | void SetM(tin::runtime::M* m) { 64 | m_ = m; 65 | } 66 | 67 | void SetStatus(uint32_t status) { 68 | status_ = status; 69 | } 70 | 71 | uint32_t GetStatus() { 72 | return status_; 73 | } 74 | 75 | uint32_t SchedTick() const { 76 | return sched_tick_; 77 | } 78 | 79 | void SetSchedTick(uint32_t sched_tick) { 80 | sched_tick_ = sched_tick; 81 | } 82 | 83 | void IncSchedTick() { 84 | sched_tick_++; 85 | } 86 | 87 | bool CasStatus(uint32_t old_status, uint32_t new_status); 88 | 89 | private: 90 | bool RunqPutSlow(G* gp, uint32_t h, uint32_t t); 91 | uint32_t RunqGrab(GUintptr* batch, int batch_size, uint32_t batch_head, 92 | bool steal_nextg); 93 | 94 | private: 95 | enum { 96 | kRunqCapacity = 256 97 | }; 98 | uint32_t runq_head_; 99 | uint32_t runq_tail_; 100 | GUintptr runq_[kRunqCapacity]; 101 | GUintptr run_next_; 102 | P* link_; 103 | int id_; 104 | uint32_t status_; 105 | uint32_t sched_tick_; 106 | tin::runtime::M* m_; 107 | }; 108 | 109 | } // namespace runtime 110 | } // namespace tin 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /tin/runtime/posix_util.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "tin/platform/platform_posix.h" 17 | #include "tin/runtime/posix_util.h" 18 | 19 | namespace tin { 20 | 21 | #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ 22 | defined(_AIX) || defined(__DragonFly__) 23 | 24 | int Nonblock(int fd, bool set) { 25 | int flag = set ? 1 : 0; 26 | return HANDLE_EINTR(ioctl(fd, FIONBIO, &flag)); 27 | } 28 | 29 | int Cloexec(int fd, bool set) { 30 | return HANDLE_EINTR(ioctl(fd, set ? FIOCLEX : FIONCLEX)); 31 | } 32 | 33 | #else 34 | 35 | // 2 syscalls version. 36 | int Nonblock(int fd, bool set) { 37 | int r = HANDLE_EINTR(fcntl(fd, F_GETFL)); 38 | if (r != -1) { 39 | /* Bail out now if already set/clear. */ 40 | if (!!(r & O_NONBLOCK) == !!set) 41 | return 0; 42 | int flags = set ? (r | O_NONBLOCK) : (r & ~O_NONBLOCK); 43 | r = HANDLE_EINTR(fcntl(fd, F_SETFL, flags)); 44 | } 45 | return r; 46 | } 47 | 48 | int Cloexec(int fd, bool set) { 49 | int r = HANDLE_EINTR(fcntl(fd, F_GETFD)); 50 | if (r != -1) { 51 | /* Bail out now if already set/clear. */ 52 | if (!!(r & FD_CLOEXEC) == !!set) 53 | return 0; 54 | int flags = set ? (r | FD_CLOEXEC) : (r & ~FD_CLOEXEC); 55 | r = HANDLE_EINTR(fcntl(fd, F_SETFD, flags)); 56 | } 57 | return r; 58 | } 59 | 60 | #endif 61 | 62 | #if defined(OS_LINUX) 63 | int Accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { 64 | #if defined(__i386__) 65 | unsigned long args[4];// NOLINT 66 | int r; 67 | 68 | args[0] = (unsigned long) fd; // NOLINT 69 | args[1] = (unsigned long) addr; // NOLINT 70 | args[2] = (unsigned long) addrlen; // NOLINT 71 | args[3] = (unsigned long) flags; // NOLINT 72 | 73 | r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args); 74 | 75 | /* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does 76 | * a bad flags argument. Try to distinguish between the two cases. 77 | */ 78 | if (r == -1) 79 | if (errno == EINVAL) 80 | if ((flags & ~(TIN__SOCK_CLOEXEC | TIN__SOCK_NONBLOCK)) == 0) 81 | errno = ENOSYS; 82 | 83 | return r; 84 | #elif defined(__NR_accept4) 85 | return syscall(__NR_accept4, fd, addr, addrlen, flags); 86 | #else 87 | errno = ENOSYS; 88 | return -1; 89 | #endif 90 | } 91 | #else 92 | int Accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { 93 | errno = ENOSYS; 94 | return -1; 95 | } 96 | #endif 97 | 98 | int Accept(int socket, struct sockaddr* address, socklen_t* address_len) { 99 | int err = 0; 100 | int fd; 101 | 102 | #if defined(OS_LINUX) 103 | fd = HANDLE_EINTR(Accept4(socket, address, address_len, 104 | TIN__SOCK_NONBLOCK | TIN__SOCK_CLOEXEC)); 105 | if (fd != -1) 106 | return fd; 107 | err = errno; 108 | if (err != ENOSYS && err != EINVAL && err != EACCES && err != EFAULT) { 109 | return -1; 110 | } 111 | #endif 112 | 113 | fd = HANDLE_EINTR(accept(socket, address, address_len)); 114 | if (fd == -1) 115 | return -1; 116 | err = Cloexec(fd, true); 117 | if (err != -1) { 118 | err = Nonblock(fd, true); 119 | } 120 | if (err != 0) { 121 | close(fd); 122 | return -1; 123 | } 124 | return fd; 125 | } 126 | 127 | } // namespace tin 128 | -------------------------------------------------------------------------------- /tin/runtime/posix_util.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include "tin/net/sys_socket.h" 8 | 9 | namespace tin { 10 | 11 | int Nonblock(int fd, bool set); 12 | 13 | int Cloexec(int fd, bool set); 14 | 15 | int Accept(int socket, struct sockaddr* address, socklen_t* address_len); 16 | 17 | } // namespace tin 18 | -------------------------------------------------------------------------------- /tin/runtime/raw_mutex.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include 8 | 9 | namespace tin::runtime { 10 | 11 | class M; 12 | class RawMutex { 13 | public: 14 | RawMutex(); 15 | RawMutex(const RawMutex&) = delete; 16 | RawMutex& operator=(const RawMutex&) = delete; 17 | ~RawMutex(); 18 | void Lock(); 19 | void Unlock(); 20 | 21 | private: 22 | uintptr_t key; 23 | M* owner_; 24 | }; 25 | 26 | class RawMutexGuard { 27 | public: 28 | inline explicit RawMutexGuard(RawMutex* lock) 29 | : lock_(lock) { 30 | lock->Lock(); 31 | } 32 | RawMutexGuard(const RawMutexGuard&) = delete; 33 | RawMutexGuard& operator=(const RawMutexGuard&) = delete; 34 | inline ~RawMutexGuard() { 35 | lock_->Unlock(); 36 | } 37 | 38 | private: 39 | RawMutex* lock_; 40 | }; 41 | 42 | class Note { 43 | public: 44 | Note(); 45 | void Wakeup(); 46 | void Sleep(); 47 | void Clear(); 48 | bool TimedSleep(int64_t ns); 49 | bool TimedSleepG(int64_t ns); 50 | 51 | private: 52 | bool SleepInternal(int64_t ns); 53 | private: 54 | uintptr_t key; 55 | }; 56 | 57 | } // namespace tin::runtime 58 | 59 | -------------------------------------------------------------------------------- /tin/runtime/runtime.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | 8 | #include "tin/error/error.h" 9 | #include "tin/runtime/util.h" 10 | #include "tin/runtime/greenlet.h" 11 | #include "tin/runtime/m.h" 12 | #include "tin/runtime/p.h" 13 | #include "tin/runtime/scheduler.h" 14 | #include "tin/runtime/timer/timer_queue.h" 15 | 16 | #include "tin/runtime/runtime.h" 17 | 18 | namespace tin { 19 | 20 | namespace runtime { 21 | 22 | void InternalLockOSThread() { 23 | G* curg = GetG(); 24 | curg->SetLockedM(curg->M()); 25 | curg->M()->SetLockedG(curg); 26 | } 27 | 28 | void InternalUnlockOSThread() { 29 | G* curg = GetG(); 30 | if (curg->M()->MutableLocked() != 0) { 31 | return; 32 | } 33 | curg->M()->SetLockedG(NULL); 34 | curg->SetLockedM(NULL); 35 | } 36 | 37 | bool YieldUnlockFn(void* arg1, void* arg2) { 38 | G* g = static_cast(arg1); 39 | 40 | // global queue. 41 | SchedulerLocker guard; 42 | sched->GlobalRunqPut(g); 43 | 44 | return true; 45 | } 46 | 47 | void InternalYield() { 48 | G* me = GetG(); 49 | Park(YieldUnlockFn, me, NULL); 50 | } 51 | 52 | } // namespace runtime 53 | 54 | void Throw(const char* str) { 55 | std::cout << str << std::endl; 56 | // base::debug::BreakDebugger(); // TODO 57 | throw(str); 58 | } 59 | 60 | void Panic(const char* str) { 61 | throw(str); 62 | } 63 | 64 | void LockOSThread() { 65 | runtime::InternalLockOSThread(); 66 | } 67 | 68 | void UnlockOSThread() { 69 | runtime::InternalUnlockOSThread(); 70 | } 71 | 72 | void SetErrorCode(int error_code) { 73 | runtime::GetG()->SetErrorCode(error_code); 74 | } 75 | 76 | int GetErrorCode() { 77 | return runtime::GetG()->GetErrorCode(); 78 | } 79 | 80 | bool ErrorOccured() { 81 | return runtime::GetG()->GetErrorCode() != 0; 82 | } 83 | 84 | const char* GetErrorStr() { 85 | return TinErrorName(GetErrorCode()); 86 | } 87 | 88 | void Sched() { 89 | tin::runtime::InternalYield(); 90 | } 91 | 92 | void NanoSleep(int64_t ns) { 93 | return tin::runtime::InternalNanoSleep(ns); 94 | } 95 | 96 | void Sleep(int64_t ms) { 97 | return NanoSleep(ms * 1000 * 1000); 98 | } 99 | 100 | } // namespace tin 101 | -------------------------------------------------------------------------------- /tin/runtime/runtime.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | 8 | namespace tin { 9 | 10 | void Throw(const char* str); 11 | 12 | void Panic(const char* str = 0); 13 | 14 | void LockOSThread(); 15 | 16 | void UnlockOSThread(); 17 | 18 | void SetErrorCode(int error_code); 19 | 20 | int GetErrorCode(); 21 | 22 | bool ErrorOccured(); 23 | 24 | const char* GetErrorStr(); 25 | 26 | // Yield conflicts with Windows macro Yield. 27 | void Sched(); 28 | 29 | void NanoSleep(int64_t ns); 30 | 31 | // sleep for ms milliseconds. 32 | void Sleep(int64_t ms); 33 | 34 | // unix time, posix time, in nano seconds. 35 | int64_t Now(); 36 | 37 | // monotonic time, system up time, in nano seconds. 38 | int64_t MonoNow(); 39 | 40 | // unix time, posix time, in seconds. 41 | int32_t NowSeconds(); 42 | 43 | } // namespace tin 44 | -------------------------------------------------------------------------------- /tin/runtime/scheduler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | 8 | #include "tin/runtime/util.h" 9 | #include "tin/runtime/guintptr.h" 10 | #include "tin/runtime/unlock.h" 11 | #include "tin/runtime/env.h" 12 | #include "tin/runtime/raw_mutex.h" 13 | 14 | namespace tin { 15 | namespace runtime { 16 | class P; 17 | class M; 18 | 19 | class Scheduler { 20 | public: 21 | Scheduler(); 22 | Scheduler(const Scheduler&) = delete; 23 | Scheduler& operator=(const Scheduler&) = delete; 24 | 25 | G* FindRunnable(bool* inherit_time); 26 | 27 | void GlobalRunqPut(G* gp); 28 | void GlobalRunqPutHead(G* gp); 29 | void GlobalRunqBatch(G* ghead, G* gtail, int32_t n); 30 | G* GlobalRunqGet(P* p, int32_t maximium); 31 | void InjectGList(G* glist); 32 | 33 | int32_t GlobalRunqSize() { 34 | return runq_size_; 35 | } 36 | 37 | void PIdlePut(P* p); 38 | P* PIdleGet(); 39 | 40 | void MPut(M* m); 41 | M* MGet(); 42 | void MGetForP(P* curp, bool spinning, P** newp, M** newm); 43 | 44 | void Reschedule(); 45 | bool OneRoundSched(G* curg); 46 | void G0Loop(); 47 | 48 | int Init(); 49 | void MakeReady(G* gp); 50 | void WakePIfNecessary(); 51 | void WakeupP(); 52 | void HandoffP(P* p); 53 | void ExitSyscall0(G* gp); 54 | bool ExitSyscallFast(); 55 | bool ExitSyscallPIdle(); 56 | void ResetSpinning(); 57 | uint32_t NrIdleP() {return nr_idlep_; } 58 | uint32_t NrSpinning() { 59 | return nr_spinning_; 60 | } 61 | 62 | uint32_t LastPollTime(); 63 | uint32_t* MutableLastPollTime() { 64 | return &last_poll_; 65 | } 66 | 67 | private: 68 | void OnSwitch(G* curg); 69 | void DoUnlock(UnLockInfo* info); 70 | P** Allp() { return allp_;} 71 | P* ResizeProc(int nprocs); 72 | 73 | private: 74 | RawMutex lock_; 75 | GUintptr runq_head_; 76 | GUintptr runq_tail_; 77 | int32_t runq_size_; 78 | 79 | P* idlep_; 80 | uint32_t nr_idlep_; 81 | uint32_t nr_spinning_; 82 | 83 | M* idlem_; // idle m's waiting for work 84 | int32_t nr_idlem_; // number of idle m's waiting for work 85 | int32_t nr_idlem_locked_; // number of locked m's waiting for work 86 | int32_t mcount_; // number of m's that have been created 87 | int32_t max_mcount_; // maximum number of m's allowed (or die) 88 | 89 | uint32_t last_poll_; 90 | 91 | P** allp_; 92 | 93 | friend class SchedulerLocker; 94 | }; 95 | 96 | 97 | class SchedulerLocker { 98 | public: 99 | SchedulerLocker() { 100 | sched->lock_.Lock(); 101 | } 102 | 103 | ~SchedulerLocker() { 104 | sched->lock_.Unlock(); 105 | } 106 | }; 107 | 108 | P* ReleaseP(); 109 | 110 | void AcquireP(P* p); 111 | 112 | void StartM(P* p, bool spinning); 113 | 114 | void ParkUnlock(RawMutex* lock); 115 | 116 | void Park(UnlockFunc unlockf = NULL, void* arg1 = NULL, void* arg2 = NULL); 117 | 118 | void Ready(G* gp); 119 | 120 | bool ParkUnlockF(void* arg1, void* arg2); 121 | 122 | void DropG(); 123 | 124 | void EnterSyscallBlock(); 125 | 126 | void ExitSyscall(); 127 | 128 | void WakePIfNecessary(); 129 | 130 | void SwitchG(Greenlet* from, Greenlet* to, intptr_t args); 131 | 132 | } // namespace runtime 133 | } // namespace tin 134 | -------------------------------------------------------------------------------- /tin/runtime/semaphore.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include "tin/runtime/util.h" 8 | 9 | 10 | namespace tin { 11 | namespace runtime { 12 | 13 | struct Sudog { 14 | G* gp; 15 | uint32_t * selectdone; 16 | Sudog* next; 17 | Sudog* prev; 18 | void* elem; // data element 19 | int32_t nrelease; 20 | Sudog* waitlink; 21 | uint32_t* address; 22 | uint32_t wakedup; 23 | 24 | Sudog() { 25 | wakedup = 0; 26 | gp = NULL; 27 | selectdone = NULL; 28 | next = NULL; 29 | prev = NULL; 30 | elem = NULL; 31 | nrelease = 0; 32 | waitlink = NULL; 33 | address = NULL; 34 | } 35 | }; 36 | 37 | bool SemAcquire(uint32_t* addr); 38 | 39 | void SemRelease(uint32_t* addr); 40 | 41 | class SyncSema { 42 | public: 43 | SyncSema() 44 | : head_(NULL) 45 | , tail_(NULL) { 46 | } 47 | SyncSema(const SyncSema&) = delete; 48 | SyncSema& operator=(const SyncSema&) = delete; 49 | void Acquire(); 50 | void Release(uint32_t n); 51 | 52 | private: 53 | RawMutex lock_; 54 | Sudog* head_; 55 | Sudog* tail_; 56 | }; 57 | 58 | } // namespace runtime 59 | } // namespace tin 60 | -------------------------------------------------------------------------------- /tin/runtime/spawn.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include 8 | 9 | namespace tin { 10 | void RuntimeSpawn(std::function* closure); 11 | 12 | inline void DoSpawn(std::function closure) { 13 | RuntimeSpawn(&closure); 14 | } 15 | 16 | template 17 | void Spawn(Functor functor, Args&&... args) { 18 | auto boundFunction = absl::bind_front(functor, std::forward(args)...); 19 | std::function closure = [boundFunction]() mutable { boundFunction(); }; 20 | DoSpawn(closure); 21 | } 22 | 23 | /* 24 | template 25 | void Spawn(Functor functor) { 26 | DoSpawn(base::Bind(functor)); 27 | } 28 | 29 | template 30 | void Spawn(Functor functor, const P1& p1) { 31 | DoSpawn(base::Bind(functor, p1)); 32 | } 33 | 34 | template 35 | void Spawn(Functor functor, const P1& p1, const P2& p2) { 36 | DoSpawn(base::Bind(functor, p1, p2)); 37 | } 38 | 39 | template 40 | void Spawn(Functor functor, const P1& p1, const P2& p2, const P3& p3) { 41 | DoSpawn(base::Bind(functor, p1, p2, p3)); 42 | } 43 | 44 | template 45 | void Spawn(Functor functor, const P1& p1, const P2& p2, const P3& p3, 46 | const P4& p4) { 47 | DoSpawn(base::Bind(functor, p1, p2, p3, p4)); 48 | } 49 | 50 | template 52 | void Spawn(Functor functor, const P1& p1, const P2& p2, const P3& p3, 53 | const P4& p4, const P5& p5) { 54 | DoSpawn(base::Bind(functor, p1, p2, p3, p4, p5)); 55 | } 56 | 57 | template 59 | void Spawn(Functor functor, const P1& p1, const P2& p2, const P3& p3, 60 | const P4& p4, const P5& p5, const P6& p6) { 61 | DoSpawn(base::Bind(functor, p1, p2, p3, p4, p5, p6)); 62 | } 63 | 64 | template 66 | void Spawn(Functor functor, const P1& p1, const P2& p2, const P3& p3, 67 | const P4& p4, const P5& p5, const P6& p6, const P7& p7) { 68 | DoSpawn(base::Bind(functor, p1, p2, p3, p4, p5, p6, p7)); 69 | } 70 | */ 71 | 72 | } // namespace tin 73 | -------------------------------------------------------------------------------- /tin/runtime/spin.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include "tin/runtime/env.h" 8 | #include "tin/runtime/greenlet.h" 9 | #include "tin/runtime/m.h" 10 | #include "tin/runtime/p.h" 11 | #include "tin/runtime/scheduler.h" 12 | #include "tin/runtime/spin.h" 13 | 14 | namespace tin { 15 | namespace runtime { 16 | 17 | bool CanSpin(int i) { 18 | int32_t max_proc = rtm_conf->MaxProcs(); 19 | if (i >= spin::kActiveSpin || 20 | rtm_env->NumberOfProcessors() <= 1 || 21 | max_proc <= 22 | static_cast(sched->NrIdleP() + sched->NrSpinning() + 1)) { 23 | return false; 24 | } 25 | if (!GetG()->M()->P()->RunqEmpty()) { 26 | return false; 27 | } 28 | return true; 29 | } 30 | 31 | void DoSpin() { 32 | YieldLogicProcessor(spin::kActiveSpinCount); 33 | return; 34 | } 35 | 36 | } // namespace runtime 37 | } // namespace tin 38 | -------------------------------------------------------------------------------- /tin/runtime/spin.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | namespace tin { 8 | namespace runtime { 9 | namespace spin { 10 | 11 | const int kActiveSpin = 4; 12 | const int kActiveSpinCount = 30; 13 | const int kPassiveSpin = 1; 14 | 15 | } // namespace spin 16 | 17 | bool CanSpin(int i); 18 | 19 | void DoSpin(); 20 | 21 | } // namespace runtime 22 | } // namespace tin 23 | -------------------------------------------------------------------------------- /tin/runtime/stack/fixedsize_stack.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include "tin/config/config.h" 8 | #include "tin/runtime/util.h" 9 | #include "tin/runtime/stack/fixedsize_stack.h" 10 | 11 | namespace tin { 12 | namespace runtime { 13 | 14 | FixedSizeStack::FixedSizeStack() 15 | : vaddr_(NULL) { 16 | } 17 | 18 | FixedSizeStack::~FixedSizeStack() { 19 | std::free(vaddr_); 20 | } 21 | 22 | // Pointer to the beginning of the stack (depending of the architecture 23 | // the stack grows downwards or upwards). 24 | void* FixedSizeStack::Allocate(size_t size) { 25 | vaddr_ = std::malloc(size); 26 | if (!vaddr_) 27 | throw std::bad_alloc(); 28 | 29 | // initialize to zero for debug build. 30 | #if !defined(NDEBUG) 31 | memset(vaddr_, 0, size); 32 | #endif 33 | vsize_ = size; 34 | // top. 35 | sp_ = static_cast(vaddr_) + size; 36 | return sp_; 37 | } 38 | 39 | } // namespace runtime 40 | } // namespace tin 41 | -------------------------------------------------------------------------------- /tin/runtime/stack/fixedsize_stack.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include "tin/runtime/stack/stack.h" 8 | 9 | namespace tin { 10 | namespace runtime { 11 | 12 | class FixedSizeStack : public Stack { 13 | public: 14 | FixedSizeStack(); 15 | 16 | virtual ~FixedSizeStack(); 17 | 18 | virtual void* Pointer() { 19 | return sp_; 20 | } 21 | 22 | virtual void* Allocate(size_t size); 23 | 24 | private: 25 | void* vaddr_; 26 | size_t vsize_; 27 | void* sp_; 28 | }; 29 | 30 | } // namespace runtime 31 | } // namespace tin 32 | 33 | -------------------------------------------------------------------------------- /tin/runtime/stack/protected_fixedsize_stack.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include "tin/runtime/stack/stack.h" 8 | 9 | namespace tin { 10 | namespace runtime { 11 | 12 | class ProtectedFixedSizeStack : public Stack { 13 | public: 14 | ProtectedFixedSizeStack(); 15 | 16 | virtual ~ProtectedFixedSizeStack(); 17 | 18 | virtual void* Pointer() { 19 | return sp_; 20 | } 21 | 22 | virtual void* Allocate(size_t size); 23 | 24 | private: 25 | size_t size_; 26 | void* sp_; 27 | }; 28 | 29 | } // namespace runtime 30 | } // namespace tin 31 | 32 | -------------------------------------------------------------------------------- /tin/runtime/stack/protected_fixedsize_stack_posix.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | extern "C" { 6 | #include 7 | #include 8 | #include 9 | #include 10 | } 11 | 12 | #include 13 | #include 14 | 15 | #include "tin/config/config.h" 16 | #include "tin/runtime/util.h" 17 | 18 | #include "tin/runtime/stack/protected_fixedsize_stack.h" 19 | 20 | namespace tin { 21 | namespace runtime { 22 | 23 | ProtectedFixedSizeStack::ProtectedFixedSizeStack() 24 | : size_(0) 25 | , sp_(NULL) { 26 | } 27 | 28 | ProtectedFixedSizeStack::~ProtectedFixedSizeStack() { 29 | if (sp_ != NULL) { 30 | void* vp = static_cast(sp_) - size_; 31 | // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) 32 | ::munmap(vp, size_); 33 | } 34 | } 35 | 36 | void* ProtectedFixedSizeStack::Allocate(size_t size) { 37 | size_t page_size = base::SysInfo::PageSize(); 38 | size_t num_pages = static_cast( 39 | std::floor(static_cast(size) / page_size)) + 1; 40 | if (num_pages < 2) 41 | num_pages = 2; 42 | size_ = num_pages * page_size; 43 | 44 | #if defined(MAP_ANON) 45 | void* vp = mmap(0, size_, 46 | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 47 | #else 48 | void* vp = mmap(0, size_, 49 | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 50 | #endif 51 | if (MAP_FAILED == vp) 52 | throw std::bad_alloc(); 53 | const int result(::mprotect(vp, page_size, PROT_NONE)); 54 | assert(0 == result); 55 | sp_ = static_cast(vp) + size_; 56 | 57 | return sp_; 58 | } 59 | 60 | } // namespace runtime 61 | } // namespace tin 62 | -------------------------------------------------------------------------------- /tin/runtime/stack/protected_fixedsize_stack_win.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include "tin/config/config.h" 10 | #include "tin/runtime/util.h" 11 | 12 | #include "tin/runtime/stack/protected_fixedsize_stack.h" 13 | 14 | namespace tin { 15 | namespace runtime { 16 | 17 | ProtectedFixedSizeStack::ProtectedFixedSizeStack() 18 | : sp_(NULL) 19 | , size_(0) { 20 | } 21 | 22 | ProtectedFixedSizeStack::~ProtectedFixedSizeStack() { 23 | if (sp_ != NULL) { 24 | void* vp = static_cast(sp_) - size_; 25 | ::VirtualFree(vp, 0, MEM_RELEASE); 26 | } 27 | } 28 | 29 | void* ProtectedFixedSizeStack::Allocate(size_t size) { 30 | size_t page_size = 4096; //base::SysInfo::PageSize(); 31 | size_t num_pages = static_cast( 32 | std::floor(static_cast(size) / page_size)) + 1; 33 | if (num_pages < 2) 34 | num_pages = 2; 35 | size_ = num_pages * page_size; 36 | 37 | void* vp = ::VirtualAlloc(0, size_, MEM_COMMIT, PAGE_READWRITE); 38 | if (!vp) 39 | throw std::bad_alloc(); 40 | 41 | // protect bottom page from any kind of access. 42 | DWORD old_options; 43 | ::VirtualProtect(vp, page_size, PAGE_READWRITE | PAGE_GUARD , &old_options); 44 | 45 | sp_ = static_cast(vp) + size_; 46 | return sp_; 47 | } 48 | 49 | } // namespace runtime 50 | } // namespace tin 51 | -------------------------------------------------------------------------------- /tin/runtime/stack/stack.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "tin/runtime/stack/fixedsize_stack.h" 11 | #include "tin/runtime/stack/protected_fixedsize_stack.h" 12 | 13 | #include "tin/runtime/stack/stack.h" 14 | 15 | namespace tin { 16 | namespace runtime { 17 | 18 | Stack* NewStack(int type, int size) { 19 | Stack* stack = NULL; 20 | switch (type) { 21 | case kFixedStack: 22 | stack = new FixedSizeStack(); 23 | break; 24 | case kProtectedFixedStack: 25 | stack = new ProtectedFixedSizeStack(); 26 | break; 27 | default: 28 | LOG(FATAL) << "invalid stack type"; 29 | } 30 | stack->Allocate(size); 31 | return stack; 32 | } 33 | 34 | } // namespace runtime 35 | } // namespace tin 36 | -------------------------------------------------------------------------------- /tin/runtime/stack/stack.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | namespace tin { 8 | namespace runtime { 9 | 10 | class Stack { 11 | public: 12 | Stack() {} 13 | virtual ~Stack() {} 14 | 15 | virtual void* Pointer() = 0; 16 | virtual void* Allocate(size_t size) = 0; 17 | 18 | private: 19 | Stack(const Stack&) = delete; 20 | Stack& operator=(const Stack&) = delete; 21 | 22 | }; 23 | 24 | enum StackType { 25 | kFixedStack = 0, 26 | kProtectedFixedStack = 1, 27 | }; 28 | 29 | Stack* NewStack(int type, int size); 30 | 31 | } // namespace runtime 32 | } // namespace tin 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /tin/runtime/sysmon.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include "tin/sync/atomic.h" 8 | #include "tin/time/time.h" 9 | #include "tin/runtime/runtime.h" 10 | #include "tin/runtime/scheduler.h" 11 | #include "tin/runtime/net/netpoll.h" 12 | 13 | #include "tin/runtime/sysmon.h" 14 | 15 | namespace tin { 16 | namespace runtime { 17 | 18 | void SysMon() { 19 | while (!rtm_env->ExitFlag()) { 20 | absl::SleepFor(absl::Milliseconds(8)); 21 | uint32_t last_poll = sched->LastPollTime(); 22 | uint32_t now = static_cast(MonoNow() / tin::kMillisecond); 23 | if (now == 0) 24 | now = 1; 25 | // no worry about uint32_t wrapping, it's well defined in C++ standard. 26 | if (NetPollInited() && last_poll != 0 && (last_poll + 10 < now)) { 27 | atomic::cas32(sched->MutableLastPollTime(), last_poll, now); 28 | G* gp = NetPoll(false); 29 | if (gp != NULL) { 30 | sched->InjectGList(gp); 31 | } 32 | } 33 | } 34 | } 35 | 36 | void SysMonJoin() { 37 | } 38 | 39 | } // namespace runtime 40 | } // namespace tin 41 | -------------------------------------------------------------------------------- /tin/runtime/sysmon.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | namespace tin { 8 | namespace runtime { 9 | 10 | void SysMon(); 11 | 12 | } // namespace runtime 13 | } // namespace tin 14 | -------------------------------------------------------------------------------- /tin/runtime/threadpoll.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include "tin/error/error.h" 8 | #include "tin/runtime/m.h" 9 | #include "tin/runtime/util.h" 10 | #include "tin/runtime/runtime.h" 11 | #include "tin/runtime/scheduler.h" 12 | 13 | #include "tin/runtime/threadpoll.h" 14 | 15 | namespace tin { 16 | namespace runtime { 17 | 18 | GletWork::GletWork() { 19 | gp_ = GetG(); 20 | } 21 | 22 | void GletWork::Resume() { 23 | { 24 | SchedulerLocker guard; 25 | sched->GlobalRunqPut(gp_); 26 | } 27 | WakePIfNecessary(); 28 | } 29 | 30 | void GletWork::Finalize() { 31 | SaveLastError(GetLastSystemErrorCode()); 32 | Resume(); 33 | } 34 | 35 | bool SubmitGletWorkUnlockF(void* arg1, void* arg2) { 36 | GletWork* work = static_cast(arg1); 37 | ThreadPoll::GetInstance()->AddWork(work); 38 | return true; 39 | } 40 | 41 | void SubmitGletWork(GletWork* work) { 42 | Park(SubmitGletWorkUnlockF, work, NULL); 43 | SetErrorCode(TinTranslateSysError(work->LastError())); 44 | } 45 | 46 | void SubmitGetAddrInfoGletWork(GletWork* work) { 47 | Park(SubmitGletWorkUnlockF, work, NULL); 48 | SetErrorCode(TinGetaddrinfoTranslateError(work->LastError())); 49 | } 50 | 51 | absl::once_flag thread_poll_once; 52 | 53 | ThreadPoll* ThreadPoll::GetInstance() { 54 | static ThreadPoll* instance = nullptr; 55 | absl::call_once(thread_poll_once, []() { 56 | instance = new ThreadPoll(); 57 | }); 58 | return instance; 59 | } 60 | 61 | // ThreadPoll implementation. 62 | ThreadPoll::ThreadPoll() 63 | : num_threads_(64) 64 | , dry_(false) { 65 | } 66 | 67 | void ThreadPoll::Start() { 68 | for (int i = 0; i < num_threads_; ++i) { 69 | // M* m = M::New(base::Bind(&ThreadPoll::Run, base::Unretained(this)), NULL); 70 | M* m = M::New(absl::bind_front(&ThreadPoll::Run, this), NULL); 71 | threads_.push_back(m); 72 | } 73 | } 74 | 75 | void ThreadPoll::JoinAll() { 76 | for (int i = 0; i < num_threads_; ++i) { 77 | AddWork(NULL); 78 | } 79 | 80 | // Join and destroy all the worker threads. 81 | for (int i = 0; i < num_threads_; ++i) { 82 | threads_[i]->Join(); 83 | delete threads_[i]; 84 | } 85 | threads_.clear(); 86 | } 87 | 88 | void ThreadPoll::AddWork(Work* work) { 89 | absl::MutexLock guard(&lock_); 90 | tasks_.push_back(work); 91 | // If we were empty, signal that we have work now. 92 | if (!dry_.HasBeenNotified()) 93 | dry_.Notify(); 94 | } 95 | 96 | // consider replace with conditional variable. 97 | void ThreadPoll::Run() { 98 | Work* work = NULL; 99 | 100 | while (true) { 101 | dry_.WaitForNotification(); 102 | { 103 | absl::MutexLock guard(&lock_); 104 | if (!dry_.HasBeenNotified()) 105 | continue; 106 | 107 | DCHECK(!tasks_.empty()); 108 | work = tasks_.front(); 109 | tasks_.pop_front(); 110 | 111 | // Signal to any other threads that we're currently out of work. 112 | if (tasks_.empty()) 113 | dry_.Notify(); // TODO 114 | } 115 | 116 | // A NULL delegate pointer signals us to quit. 117 | if (!work) 118 | break; 119 | 120 | work->Run(); 121 | } 122 | } 123 | 124 | } // namespace runtime 125 | } // namespace tin 126 | -------------------------------------------------------------------------------- /tin/runtime/threadpoll.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #include "tin/runtime/env.h" 16 | 17 | namespace tin { 18 | namespace runtime { 19 | 20 | class M; 21 | // consider replace with shared_ptr 22 | class Work { 23 | public: 24 | Work() { } 25 | Work(const Work&) = delete; 26 | Work& operator=(const Work&) = delete; 27 | virtual ~Work() { } 28 | virtual void Run() = 0; 29 | }; 30 | 31 | class GletWork : public Work { 32 | public: 33 | GletWork(); 34 | virtual ~GletWork() {} 35 | virtual void Run() = 0; 36 | int LastError() const {return last_error_;} 37 | void SaveLastError(int err) {last_error_ = err;} 38 | 39 | protected: 40 | void Resume(); 41 | void Finalize(); 42 | 43 | private: 44 | int last_error_; 45 | G* gp_; 46 | }; 47 | 48 | void SubmitGletWork(GletWork* work); 49 | void SubmitGetAddrInfoGletWork(GletWork* work); 50 | 51 | 52 | class ThreadPoll { 53 | public: 54 | ThreadPoll(const ThreadPoll&) = delete; 55 | ThreadPoll& operator=(const ThreadPoll&) = delete; 56 | 57 | static ThreadPoll* GetInstance(); 58 | 59 | void Start(); 60 | void JoinAll(); 61 | void AddWork(Work* work); 62 | void Run(); 63 | 64 | private: 65 | ThreadPoll(); 66 | private: 67 | int num_threads_; 68 | std::vector threads_; 69 | std::deque tasks_; 70 | absl::Mutex lock_; 71 | 72 | absl::Notification dry_; 73 | }; 74 | 75 | } // namespace runtime 76 | } // namespace tin 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /tin/runtime/timer/timer_queue.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | 8 | #include "tin/time/time.h" 9 | #include "tin/sync/wait_group.h" 10 | #include "tin/runtime/util.h" 11 | #include "tin/runtime/raw_mutex.h" 12 | 13 | namespace tin { 14 | namespace runtime { 15 | 16 | void InternalNanoSleep(int64_t ns); 17 | 18 | typedef void (*TimerCallback)(void* arg, uintptr_t seq); 19 | 20 | int64_t NanoFromNow(int64_t deadline); 21 | 22 | struct Timer { 23 | Timer() { 24 | i = 0; 25 | when = period = 0; 26 | seq = 0; 27 | f = NULL; 28 | arg = 0; 29 | } 30 | 31 | int i; 32 | int64_t when; 33 | int64_t period; 34 | uintptr_t seq; 35 | TimerCallback f; 36 | void* arg; 37 | }; 38 | 39 | class TimerQueue { 40 | public: 41 | TimerQueue(); 42 | ~TimerQueue(); 43 | 44 | TimerQueue(const TimerQueue&) = delete; 45 | TimerQueue& operator=(const TimerQueue&) = delete; 46 | 47 | void AddTimerLocked(Timer* t); 48 | void AddTimer(Timer* t); 49 | bool DelTimer(Timer* t); 50 | void Lock(); 51 | void Join(); 52 | static bool UnlockQueue(void* arg1, void* arg2); 53 | 54 | private: 55 | void Proc(); 56 | void SiftUp(int i); 57 | void SiftDown(int i); 58 | 59 | int Length() { 60 | return static_cast(timers_.size()); 61 | } 62 | 63 | private: 64 | G* gp_; 65 | bool created_; 66 | bool rescheduling_; 67 | bool sleeping_; 68 | RawMutex mutex_; 69 | Note wait_note_; 70 | std::vector timers_; 71 | bool exit_flag_; 72 | tin::WaitGroup wait_group_; 73 | 74 | 75 | 76 | }; 77 | 78 | 79 | } // namespace runtime 80 | } // namespace tin 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /tin/runtime/unlock.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include "tin/runtime/p.h" 8 | #include "tin/runtime/greenlet.h" 9 | #include "tin/runtime/unlock.h" 10 | 11 | namespace tin { 12 | namespace runtime { 13 | 14 | void UnLockInfo::RunInternal() { 15 | if (!f_(arg1_, arg2_)) { 16 | owner_->SetState(GLET_RUNNABLE); 17 | GetP()->RunqPut(owner_, false); 18 | } 19 | Clear(); 20 | } 21 | 22 | } // namespace runtime 23 | } // namespace tin 24 | -------------------------------------------------------------------------------- /tin/runtime/unlock.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | 8 | #include "tin/runtime/util.h" 9 | 10 | namespace tin { 11 | namespace runtime { 12 | 13 | // return false if resumed. 14 | typedef bool(*UnlockFunc)(void* arg1, void* arg2); 15 | 16 | class UnLockInfo { 17 | public: 18 | UnLockInfo() 19 | : f_(NULL) 20 | , arg1_(NULL) 21 | , arg2_(NULL) 22 | , owner_(NULL) { 23 | } 24 | 25 | UnLockInfo(const UnLockInfo&) = delete; 26 | UnLockInfo& operator=(const UnLockInfo&) = delete; 27 | 28 | UnlockFunc F() const { 29 | return f_; 30 | } 31 | 32 | void* Arg1() const { 33 | return arg1_; 34 | } 35 | 36 | void* Arg2() const { 37 | return arg2_; 38 | } 39 | 40 | G* Owner() const { 41 | return owner_; 42 | } 43 | 44 | bool Empty() const { 45 | return f_ == NULL; 46 | } 47 | 48 | // set 49 | void Set(UnlockFunc unlockf, void* arg1, void* arg2, G* owner) { 50 | f_ = unlockf; 51 | arg1_ = arg1; 52 | arg2_ = arg2; 53 | owner_ = owner; 54 | } 55 | 56 | void SetF(UnlockFunc unlockf) { 57 | f_ = unlockf; 58 | } 59 | 60 | void SetArg1(void* arg) { 61 | arg1_ = arg; 62 | } 63 | 64 | void SetArg2(void* arg) { 65 | arg2_ = arg; 66 | } 67 | 68 | void SetOwner(G* owner) { 69 | owner_ = owner; 70 | } 71 | 72 | void Clear() { 73 | f_ = NULL; 74 | arg1_ = NULL; 75 | arg2_ = NULL; 76 | owner_ = NULL; 77 | } 78 | 79 | void Run() { 80 | if (f_ != NULL) 81 | RunInternal(); 82 | } 83 | 84 | private: 85 | void RunInternal(); 86 | 87 | private: 88 | UnlockFunc f_; 89 | void* arg1_; 90 | void* arg2_; 91 | G* owner_; 92 | }; 93 | 94 | } // namespace runtime 95 | } // namespace tin 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /tin/runtime/util.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include "tin/runtime/util.h" 7 | 8 | #if defined(OS_WIN) 9 | #include 10 | #else 11 | #include 12 | #include 13 | #endif 14 | 15 | namespace tin { 16 | namespace runtime { 17 | 18 | void YieldLogicProcessor() { 19 | #if defined(OS_WIN) 20 | YieldProcessor(); 21 | #elif defined(ARCH_CPU_X86_FAMILY) 22 | __asm__ __volatile__("pause"); 23 | #elif defined(ARCH_CPU_ARM_FAMILY) 24 | // ARMv6K and above, disable currently. 25 | // __asm__ __volatile__("yield"); 26 | #elif defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS) 27 | __asm__ __volatile__(".word 0x00000140"); 28 | #elif defined(ARCH_CPU_MIPS_FAMILY) && __mips_isa_rev >= 2 29 | __asm__ __volatile__("pause"); 30 | #else 31 | // do nothing. 32 | #endif 33 | } 34 | 35 | void YieldLogicProcessor(int n) { 36 | for (int i = 0; i < n; ++i) { 37 | YieldLogicProcessor(); 38 | } 39 | } 40 | 41 | int GetLastSystemErrorCode() { 42 | #if defined(OS_WIN) 43 | return ::GetLastError(); 44 | #elif defined(OS_POSIX) 45 | return errno; 46 | #else 47 | #error Not implemented 48 | #endif 49 | } 50 | 51 | } // namespace runtime 52 | } // namespace tin 53 | -------------------------------------------------------------------------------- /tin/runtime/util.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include "tin/runtime/env.h" 10 | 11 | namespace tin { 12 | namespace runtime { 13 | 14 | class Greenlet; 15 | class P; 16 | class M; 17 | typedef Greenlet G; 18 | 19 | inline G* GetG() { 20 | return glet_tls; 21 | } 22 | 23 | inline void SetG(G* gp) { 24 | glet_tls = gp; 25 | } 26 | 27 | P* GetP(); 28 | 29 | M* GetM(); 30 | 31 | inline uintptr_t GpCast(G* gp) { 32 | return reinterpret_cast(gp); 33 | } 34 | 35 | inline G* GpCastBack(uintptr_t gp) { 36 | return reinterpret_cast(gp); 37 | } 38 | 39 | void YieldLogicProcessor(); 40 | void YieldLogicProcessor(int n); 41 | int GetLastSystemErrorCode(); 42 | 43 | } // namespace runtime 44 | } // namespace tin 45 | -------------------------------------------------------------------------------- /tin/sync/atomic_flag.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | 8 | #include "cstdint" 9 | 10 | #include "tin/sync/atomic.h" 11 | 12 | namespace tin { 13 | 14 | class AtomicFlag { 15 | public: 16 | explicit AtomicFlag(bool flag = false) 17 | : flag_(flag ? 1 : 0) { 18 | } 19 | AtomicFlag(const AtomicFlag&) = delete; 20 | AtomicFlag& operator=(const AtomicFlag&) = delete; 21 | ~AtomicFlag() { 22 | } 23 | 24 | operator bool() const { 25 | return atomic::acquire_load32(&flag_) == 1; 26 | } 27 | 28 | AtomicFlag& operator=(bool flag) { 29 | atomic::release_store32(&flag_, flag ? 1 : 0); 30 | return *this; 31 | } 32 | 33 | private: 34 | uint32_t flag_; 35 | }; 36 | 37 | } // namespace tin 38 | -------------------------------------------------------------------------------- /tin/sync/cond.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | 8 | #include "tin/sync/atomic.h" 9 | #include "tin/runtime/raw_mutex.h" 10 | 11 | #include "tin/sync/cond.h" 12 | 13 | namespace tin { 14 | 15 | void Cond::Wait() { 16 | atomic::Inc32(&waiters_, 1); 17 | lock_->Unlock(); 18 | sem_.Acquire(); 19 | lock_->Lock(); 20 | } 21 | 22 | void Cond::Signal() { 23 | SignalImpl(false); 24 | } 25 | 26 | void Cond::Broascast() { 27 | SignalImpl(true); 28 | } 29 | 30 | void Cond::SignalImpl(bool all) { 31 | while (true) { 32 | uint32_t old_waiters = atomic::load32(&waiters_); 33 | if (old_waiters == 0) { 34 | return; 35 | } 36 | uint32_t new_waiters = old_waiters - 1; 37 | if (all) { 38 | new_waiters = 0; 39 | } 40 | if (atomic::cas32(&waiters_, old_waiters, new_waiters)) { 41 | sem_.Release(old_waiters - new_waiters); 42 | } 43 | } 44 | } 45 | 46 | } // namespace tin 47 | -------------------------------------------------------------------------------- /tin/sync/cond.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | 8 | #include 9 | 10 | #include "tin/runtime/semaphore.h" 11 | #include "tin/sync/mutex.h" 12 | 13 | namespace tin { 14 | 15 | class Cond { 16 | public: 17 | explicit Cond(Mutex* lock) 18 | : lock_(lock) 19 | , waiters_(0) { 20 | } 21 | Cond(const Cond&) = delete; 22 | Cond& operator=(const Cond&) = delete; 23 | void Wait(); 24 | void Signal(); 25 | void Broascast(); 26 | 27 | private: 28 | void SignalImpl(bool all); 29 | 30 | private: 31 | Mutex* lock_; 32 | runtime::SyncSema sem_; 33 | uint32_t waiters_; 34 | }; 35 | 36 | } // namespace tin 37 | -------------------------------------------------------------------------------- /tin/sync/mutex.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | 8 | #include "tin/sync/atomic.h" 9 | #include "tin/runtime/raw_mutex.h" 10 | #include "tin/runtime/spin.h" 11 | #include "tin/runtime/semaphore.h" 12 | 13 | #include "tin/sync/mutex.h" 14 | 15 | namespace tin { 16 | 17 | namespace { 18 | const int32_t kMutexLocked = 1; // mutex is locked 19 | const int32_t kMutexWoken = 2; 20 | const int32_t kMutexWaiterShift = 2; 21 | } 22 | 23 | Mutex::Mutex() 24 | : state_(0) 25 | , sema_(0) { 26 | } 27 | 28 | Mutex::~Mutex() { 29 | } 30 | 31 | void Mutex::Lock() { 32 | if (atomic::cas32(&state_, 0, kMutexLocked)) { 33 | return; 34 | } 35 | bool awoke = false; 36 | int32_t iter = 0; 37 | while (true) { 38 | int32_t old_state = state_; 39 | int32_t new_state = old_state | kMutexLocked; 40 | if ((old_state & kMutexLocked) != 0) { 41 | if (tin::runtime::CanSpin(iter)) { 42 | // Active spinning makes sense. 43 | // Try to set mutexWoken flag to inform Unlock 44 | // to not wake other blocked goroutines. 45 | if ((!awoke) && 46 | ((old_state & kMutexWoken) == 0) && 47 | ((old_state >> kMutexWaiterShift) != 0) && 48 | atomic::cas32(&state_, old_state, old_state | kMutexWoken)) { 49 | awoke = true; 50 | } 51 | tin::runtime::DoSpin(); 52 | iter++; 53 | continue; 54 | } 55 | new_state = old_state + (1 << kMutexWaiterShift); 56 | } 57 | if (awoke) { 58 | // The goroutine has been woken from sleep, 59 | // so we need to reset the flag in either case. 60 | if ((new_state & kMutexWoken) == 0) { 61 | LOG(FATAL) << "sync: inconsistent mutex state"; 62 | } 63 | // clear mutexWoken bit. 64 | new_state &= ~kMutexWoken; 65 | } 66 | if (atomic::cas32(&state_, old_state, new_state)) { 67 | if ((old_state & kMutexLocked) == 0) 68 | break; 69 | tin::runtime::SemAcquire(&sema_); 70 | awoke = true; 71 | iter = 0; 72 | } 73 | } 74 | } 75 | 76 | void Mutex::Unlock() { 77 | // Fast path: drop lock bit 78 | int32_t new_state = atomic::Inc32(&state_, -kMutexLocked); 79 | if (((new_state + kMutexLocked)&kMutexLocked) == 0) { 80 | LOG(FATAL) << "sync: unlock of unlocked mutex"; 81 | } 82 | 83 | int32_t old_state = new_state; 84 | while (true) { 85 | // If there are no waiters or a goroutine has already 86 | // been woken or grabbed the lock, no need to wake anyone. 87 | if ((old_state >> kMutexWaiterShift) == 0 || 88 | (old_state & (kMutexLocked | kMutexWoken)) != 0) { 89 | return; 90 | } 91 | // Grab the right to wake someone. 92 | new_state = (old_state - (1 << kMutexWaiterShift)) | kMutexWoken; 93 | if (atomic::cas32(&state_, old_state, new_state)) { 94 | tin::runtime::SemRelease(&sema_); 95 | } 96 | old_state = state_; 97 | } 98 | } 99 | 100 | } // namespace tin 101 | -------------------------------------------------------------------------------- /tin/sync/mutex.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include 8 | 9 | namespace tin { 10 | 11 | // Mutex is a Futex implementation. 12 | class Mutex { 13 | public: 14 | Mutex(); 15 | Mutex(const Mutex&) = delete; 16 | Mutex& operator=(const Mutex&) = delete; 17 | ~Mutex(); 18 | void Lock(); 19 | void Unlock(); 20 | 21 | private: 22 | int32_t state_; 23 | uint32_t sema_; 24 | }; 25 | 26 | class MutexGuard { 27 | public: 28 | inline explicit MutexGuard(Mutex* lock) 29 | : lock_(lock) { 30 | lock->Lock(); 31 | } 32 | MutexGuard(const MutexGuard&) = delete; 33 | MutexGuard& operator=(const MutexGuard&) = delete; 34 | inline ~MutexGuard() { 35 | lock_->Unlock(); 36 | } 37 | 38 | private: 39 | Mutex* lock_; 40 | }; 41 | 42 | 43 | } // namespace tin 44 | -------------------------------------------------------------------------------- /tin/sync/rwmutex.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | 8 | #include "tin/sync/atomic.h" 9 | #include "tin/runtime/raw_mutex.h" 10 | #include "tin/runtime/semaphore.h" 11 | 12 | #include "tin/sync/rwmutex.h" 13 | 14 | namespace tin { 15 | 16 | namespace { 17 | const int32_t kRWMutexMaxReaders = 1 << 30; 18 | } 19 | 20 | RWMutex::RWMutex() 21 | : writer_sem_(0) 22 | , reader_sem(0) 23 | , reader_count_(0) 24 | , reader_wait_(0) { 25 | } 26 | 27 | RWMutex::~RWMutex() { 28 | } 29 | 30 | void RWMutex::RLock() { 31 | if (atomic::Inc32(&reader_count_, 1) < 0) { 32 | runtime::SemAcquire(&reader_sem); 33 | } 34 | } 35 | 36 | void RWMutex::RUnlock() { 37 | int32_t r = atomic::Inc32(&reader_count_, -1); 38 | if (r < 0) { 39 | if (r + 1 == 0 || r + 1 == -kRWMutexMaxReaders) { 40 | LOG(FATAL) << "sync: RUnlock of unlocked RWMutex"; 41 | } 42 | if (atomic::Inc32(&reader_wait_, -1) == 0) { 43 | runtime::SemRelease(&writer_sem_); 44 | } 45 | } 46 | } 47 | 48 | void RWMutex::Lock() { 49 | w_.Lock(); 50 | int32_t r = 51 | atomic::Inc32(&reader_count_, -kRWMutexMaxReaders) + kRWMutexMaxReaders; 52 | if (r != 0 && atomic::Inc32(&reader_wait_, r) != 0) { 53 | runtime::SemAcquire(&writer_sem_); 54 | } 55 | } 56 | 57 | void RWMutex::Unlock() { 58 | int32_t r = atomic::Inc32(&reader_count_, kRWMutexMaxReaders); 59 | if (r >= kRWMutexMaxReaders) { 60 | LOG(FATAL) << "sync: Unlock of unlocked RWMutex"; 61 | } 62 | 63 | for (int32_t i = 0; i < r; i++) { 64 | runtime::SemRelease(&reader_sem); 65 | } 66 | w_.Unlock(); 67 | } 68 | 69 | } // namespace tin 70 | -------------------------------------------------------------------------------- /tin/sync/rwmutex.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include 8 | #include 9 | #include "tin/sync/mutex.h" 10 | 11 | namespace tin { 12 | 13 | class RWMutex { 14 | public: 15 | RWMutex(); 16 | RWMutex(const RWMutex&) = delete; 17 | RWMutex& operator=(const RWMutex&) = delete; 18 | ~RWMutex(); 19 | 20 | 21 | void RLock(); 22 | void RUnlock(); 23 | void Lock(); 24 | void Unlock(); 25 | 26 | private: 27 | Mutex w_; // held if there are pending writers 28 | uint32_t writer_sem_; // semaphore for writers to wait for completing readers 29 | uint32_t reader_sem; // semaphore for readers to wait for completing writers 30 | int32_t reader_count_; // number of pending readers 31 | int32_t reader_wait_; // number of departing readers 32 | }; 33 | 34 | class MutexReaderGuard { 35 | public: 36 | inline explicit MutexReaderGuard(RWMutex* lock) 37 | : lock_(lock) { 38 | lock->RLock(); 39 | } 40 | MutexReaderGuard(const MutexReaderGuard&) = delete; 41 | MutexReaderGuard& operator=(const MutexReaderGuard&) = delete; 42 | inline ~MutexReaderGuard() { 43 | lock_->RUnlock(); 44 | } 45 | 46 | private: 47 | RWMutex* lock_; 48 | }; 49 | 50 | class MutexWriterGuard { 51 | public: 52 | inline explicit MutexWriterGuard(RWMutex* lock) 53 | : lock_(lock) { 54 | lock->Lock(); 55 | } 56 | MutexWriterGuard(const MutexWriterGuard&) = delete; 57 | MutexWriterGuard& operator=(const MutexWriterGuard&) = delete; 58 | inline ~MutexWriterGuard() { 59 | lock_->Unlock(); 60 | } 61 | 62 | private: 63 | RWMutex* lock_; 64 | }; 65 | 66 | } // namespace tin 67 | -------------------------------------------------------------------------------- /tin/sync/wait_group.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | 8 | #include "tin/sync/atomic.h" 9 | #include "tin/runtime/raw_mutex.h" 10 | #include "tin/runtime/semaphore.h" 11 | 12 | #include "tin/sync/wait_group.h" 13 | 14 | namespace tin { 15 | 16 | WaitGroup::WaitGroup(int delta /*= 0*/) 17 | : state_(0) 18 | , sem_(0) { 19 | if (delta != 0) { 20 | Add(delta); 21 | } 22 | } 23 | 24 | WaitGroup::~WaitGroup() { 25 | } 26 | 27 | void WaitGroup::Add(int32_t delta) { 28 | uint64_t delta64 = delta; 29 | delta64 <<= 32; 30 | uint64_t state = state_.fetch_add(delta64) + delta64; 31 | int32_t v = static_cast(state >> 32); // high 32 bits: counter. 32 | uint32_t w = static_cast(state); // lower 32 bits: waiter. 33 | if (v < 0) { 34 | LOG(FATAL) << "sync: negative WaitGroup counter"; 35 | } 36 | if (w != 0 && delta > 0 && v == delta) { 37 | LOG(FATAL) << "sync: negative WaitGroup counter"; 38 | } 39 | if (v > 0 || w == 0) { 40 | return; 41 | } 42 | if (state != state_) { 43 | LOG(FATAL) << "sync: WaitGroup misuse: Add called concurrently with Wait"; 44 | } 45 | state_ = 0; 46 | for ( ; w != 0; w--) { 47 | runtime::SemRelease(&sem_); 48 | } 49 | } 50 | 51 | void WaitGroup::Done() { 52 | Add(-1); 53 | } 54 | 55 | void WaitGroup::Wait() { 56 | while (true) { 57 | uint64_t state = state_; 58 | int32_t v = static_cast(state >> 32); // high 32 bits: counter. 59 | uint32_t w = static_cast(state); // lower 32 bits: waiter. 60 | (void)w; 61 | if (v == 0) 62 | return; 63 | if (state_.compare_exchange_strong(state, state + 1)) { 64 | runtime::SemAcquire(&sem_); 65 | if (state_ != 0) { 66 | LOG(FATAL) 67 | << "sync: WaitGroup is reused before previous Wait has returned"; 68 | } 69 | return; 70 | } 71 | } 72 | return; 73 | } 74 | 75 | } // namespace tin 76 | -------------------------------------------------------------------------------- /tin/sync/wait_group.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | #include "quark/atomic.hpp" 8 | #include "tin/sync/mutex.h" 9 | 10 | namespace tin { 11 | 12 | class WaitGroup { 13 | public: 14 | explicit WaitGroup(int delta = 0); 15 | WaitGroup(const WaitGroup&) = delete; 16 | WaitGroup& operator=(const WaitGroup&) = delete; 17 | ~WaitGroup(); 18 | 19 | void Add(int32_t delta); 20 | void Done(); 21 | void Wait(); 22 | 23 | private: 24 | quark::atomic_uint64_t state_; 25 | uint32_t sem_; 26 | }; 27 | 28 | 29 | 30 | 31 | } // namespace tin 32 | -------------------------------------------------------------------------------- /tin/time/time.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "tin/time/time.h" 6 | -------------------------------------------------------------------------------- /tin/time/time.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | 8 | namespace tin { 9 | 10 | const int64_t kNanosecond = 1; 11 | const int64_t kMicrosecond = 1000 * kNanosecond; 12 | const int64_t kMillisecond = 1000 * kMicrosecond; 13 | const int64_t kSecond = 1000 * kMillisecond; 14 | const int64_t kMinute = 60 * kSecond; 15 | const int64_t kHour = 60 * kMinute; 16 | 17 | } // namespace tin 18 | -------------------------------------------------------------------------------- /tin/tin.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "tin/runtime/env.h" 6 | #include "tin/platform/platform.h" 7 | 8 | #include "tin/tin.h" 9 | 10 | #include 11 | #include 12 | namespace tin { 13 | 14 | namespace { 15 | Config* conf = NULL; 16 | } 17 | 18 | void Initialize() { 19 | std::string name = "John"; int age = 25; 20 | 21 | std::string formatted_string = absl::StrFormat("My name is %s and I am %d years old.", name, age); std::cout << formatted_string << std::endl; 22 | conf = new tin::Config; 23 | *conf = DefaultConfig(); 24 | PlatformInit(); 25 | } 26 | 27 | void PowerOn(EntryFn fn, int argc, char** argv, Config* new_conf) { 28 | if (new_conf != NULL) { 29 | *conf = *new_conf; 30 | } 31 | runtime::InitializeEnv(fn, argc, argv, conf); 32 | } 33 | 34 | void PowerOn(EntryFn fn, Config* new_conf) { 35 | return PowerOn(fn, 0, NULL, new_conf); 36 | } 37 | 38 | int WaitForPowerOff() { 39 | return runtime::rtm_env->WaitMainExit(); 40 | } 41 | 42 | void Deinitialize() { 43 | delete conf; 44 | } 45 | 46 | Config* GetWorkingConfig() { 47 | return conf; 48 | } 49 | 50 | Config DefaultConfig() { 51 | Config conf; 52 | conf.SetMaxProcs(1); 53 | conf.SetStackSize(kDefaultStackSize); 54 | conf.SetOsThreadStackSize(kDefaultOSThreadStackSize); 55 | conf.SetIgnoreSigpipe(true); 56 | conf.EnableStackPprotection(false); 57 | return conf; 58 | } 59 | 60 | } // namespace tin 61 | -------------------------------------------------------------------------------- /tin/tin.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include "tin/config/config.h" 7 | 8 | namespace tin { 9 | 10 | typedef int(*EntryFn)(int argc, char** argv); 11 | 12 | void Initialize(); 13 | 14 | void PowerOn(EntryFn fn, int argc, char** argv, Config* new_conf); 15 | 16 | void PowerOn(EntryFn fn, Config* new_conf); 17 | 18 | int WaitForPowerOff(); 19 | 20 | void Deinitialize(); 21 | 22 | Config* GetWorkingConfig(); 23 | 24 | Config DefaultConfig(); 25 | 26 | } // namespace tin 27 | -------------------------------------------------------------------------------- /tin/util/unique_id.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include "tin/sync/mutex.h" 8 | #include "tin/util/unique_id.h" 9 | #include "quark/atomic.hpp" 10 | 11 | namespace tin { 12 | 13 | class UniqueIdGenerator { 14 | public: 15 | 16 | UniqueIdGenerator() 17 | : uid_(0) { 18 | } 19 | 20 | uint64_t Next() { 21 | uint64_t uid = uid_.fetch_add(1) + 1; 22 | return uid; 23 | } 24 | private: 25 | mutable tin::Mutex mutex_; 26 | std::atomic uid_; 27 | }; 28 | 29 | UniqueIdGenerator UniqueIdGeneratorInst; 30 | 31 | uint64_t GetUniqueId() { 32 | return UniqueIdGeneratorInst.Next(); 33 | } 34 | 35 | } // namespace tin. 36 | -------------------------------------------------------------------------------- /tin/util/unique_id.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Tin Project. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #pragma once 6 | #include 7 | 8 | namespace tin { 9 | 10 | uint64_t GetUniqueId(); 11 | 12 | } // namespace tin. 13 | --------------------------------------------------------------------------------