-
-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support for non-blocking network IO
This adds support for performing non-blocking network operations, such as reading and writing to/from a socket. The runtime API exposed is similar to Erlang, allowing one to write code that uses non-blocking APIs without having to resort to using callbacks. For example, in a typicall callback based language you may write the following to read from a socket: socket.create do (socket) { socket.read do (data) { } } In Inko, you instead would (more or less) write the following: import std::net::socket::TcpStream let socket = try! TcpStream.new(ip: '192.0.2.0', port: 80) let message = try! socket.read_string(size: 4) The VM then takes care of using the appropriate non-blocking operations, and will reschedule processes whenever necessary. This functionality is exposed through the following runtime modules: * std::net::ip: used for parsing IPv4 and IPv6 addresses. * std::net::socket: used for TCP and UDP sockets. * std::net::unix: used for Unix domain sockets. The VM uses the system's native polling mechanism to determine when a file descriptor is available for a read or write. On Linux we use epoll, while using kqueue for the various BSDs and Mac OS. For Windows we use wepoll (https://github.com/piscisaureus/wepoll). Wepoll exposes an API that is compatible with the epoll API, but uses Windows IO completion ports under the hoods. When a process attempts to perform a non-blocking operation, the process is registered (combined with the file descriptor to poll) in a global poller and suspended. When the file descriptor becomes available for a read or write, the corresponding process is rescheduled. The polling mechanism is set up in such a way that a process can not be rescheduled multiple times at once. We do not use MIO (https://github.com/tokio-rs/mio), instead we use epoll, kqueue, and wepoll (using https://crates.io/crates/wepoll-binding) directly. At the time of writing, while MIO offers some form of support for Windows it comes with various issues: 1. tokio-rs/mio#921 2. tokio-rs/mio#919 3. tokio-rs/mio#776 4. tokio-rs/mio#913 It's not clear when these issues would be addressed, as the maintainers of MIO appear to not have the experience and resources to resolve them themselves. MIO is part of the Google Summer of Code 2019, with the goal of improving Windows support. Unfortunately, this likely won't be done before the end of 2019, and we don't want to wait that long. Another issue with MIO is its implementation. Internally, MIO uses various forms of synchronisation which can make it expensive to use a single poller across multiple threads; it certainly is not a zero-cost library. It also offers more than we need, such as being able to poll arbitrary objects. We are not the first to run into these issues. For example, the Amethyst video game engine also ran into issues with MIO as detailed in https://community.amethyst.rs/t/sorting-through-the-mio-mess/561. With all of this in mind, I decided it was not worth the time to wait for MIO to get fixed, and to instead spend time directly using epoll, kqueue, and wepoll. This gives us total control over the code, and allows us to implement what we need in the way we need it. Most important of all: it works on Linux, BSD, Mac, and Windows.
- Loading branch information
Yorick Peterse
committed
May 9, 2019
1 parent
99c9f04
commit 3974f47
Showing
58 changed files
with
7,443 additions
and
549 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,5 +18,7 @@ module PrototypeID | |
FUNCTION = 13 | ||
POINTER = 14 | ||
PROCESS = 15 | ||
SOCKET = 16 | ||
UNIX_SOCKET = 17 | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#! Extensions for the `Integer` type that can only be defined later on in the | ||
#! bootstrapping process. | ||
import std::process | ||
import std::string_buffer::StringBuffer | ||
|
||
## The digits to use when converting an `Integer` to a `String` using a specific | ||
## base or radix. | ||
## | ||
## The order of values in this `Array` must remain as-is, as re-ordering values | ||
## will break the code that uses this `Array`. | ||
let INTEGER_RADIX_DIGITS = [ | ||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', | ||
'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | ||
'u', 'v', 'w', 'x', 'y', 'z' | ||
] | ||
|
||
impl Integer { | ||
## Formats `self` as a `String` using the given base/radix. | ||
## | ||
## # Panics | ||
## | ||
## This method will panic if `radix` is smaller than 2, or greater than 36. | ||
## | ||
## # Examples | ||
## | ||
## Formatting an integer in base 16 (hexadecimal): | ||
## | ||
## 0x2ff.format(radix: 16) # => '2ff' | ||
def format(radix = 10) -> String { | ||
radix < 2 | ||
.or { radix > 36 } | ||
.if_true { | ||
process.panic('The radix argument must be between 2 and 36') | ||
} | ||
|
||
zero?.if_true { | ||
return '0' | ||
} | ||
|
||
let characters = [] | ||
let mut integer = absolute | ||
|
||
negative?.if_true { | ||
characters.push('-') | ||
} | ||
|
||
{ integer.positive? }.while_true { | ||
characters.push(*INTEGER_RADIX_DIGITS[integer % radix]) | ||
integer /= radix | ||
} | ||
|
||
# The above operation pushes the digits from the back, resulting in our | ||
# characters being in reverse order. For example, for 0x2ff the `characters` | ||
# `Array` would be `['f', 'f', '2']`. Below we'll reverse the values | ||
# in-place. | ||
let start_at = negative?.if true: { 1 }, false: { 0 } | ||
let mut old_index = characters.length - 1 | ||
let mut new_index = start_at | ||
|
||
{ old_index > new_index }.while_true { | ||
let old = *characters[old_index] | ||
let new = *characters[new_index] | ||
|
||
characters[new_index] = old | ||
characters[old_index] = new | ||
|
||
old_index -= 1 | ||
new_index += 1 | ||
} | ||
|
||
StringBuffer.new(characters).to_string | ||
} | ||
} |
Oops, something went wrong.