- 08 Jul, 2019 7 commits
-
-
Kenton Varda authored
For whatever reason, the default termination handler on my machine is no longer printing the exception's `what()` string. It just aborts. That makes debugging hard. This also means that we can now use `noexcept` in unit tests as a way to make uncaught exceptions abort the process _without_ unwinding, which is especially useful in tests that create threads since they often deadlock during unwind waiting for the thread to finish.
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
The new `Executor` class provides an interface to run a function on some other thread's EventLoop. `kj::getCurrentThreadExecutor()` gets a reference to this thread's executor, which can then be exposed to other threads. When a thread requests execution of a function on another thread, the return value is returned to the requesting thread. The requesting thread may choose to wait synchronously for this return value or -- if the requesting thread has an event loop of its own -- it can get Promise for the eventual result. Meanwhile, orthogonally, the function can either return a raw result or return a Promise; in the latter case, the Promise is resolved to completion in the executor thread and the final result is sent back to the requesting thread.
-
- 01 Jul, 2019 2 commits
-
-
Kenton Varda authored
This is better than `MutexGuarded<T>::when()` in cases where the caller already has a lock -- `when()` would require unlocking, then immediately locking again (to check the predicate). Possibly `when()` should be removed in favor of `wait()`.
-
Kenton Varda authored
-
- 30 Jun, 2019 1 commit
-
-
Kenton Varda authored
This will be important in subsequent commits adding cross-thread events to EventLoop. We'll only want wait() to throw if we know no cross-thread events will ever come, but the EventPort won't know that, only the EventLoop will.
-
- 28 Jun, 2019 1 commit
-
-
Kenton Varda authored
I had a snarky comment in the Windows code being annoyed that mapping an empty file was documented to fail... but it turns out zero-length mappings fail on Linux, too. Also my work-around on Windows didn't work (but was never tested). This PR fixes both. This was prompted by @KubaO observing that `capnp compile` on an empty source file failed with a cryptic mmap error. Closes #854, @KubaO's attempt at fixing this, since the correct fix is in the filesystem API, not in the compiler.
-
- 26 Jun, 2019 4 commits
-
-
Kenton Varda authored
I didn't bother for posix condvars since they're kind of explicitly tied to posix clocks and it would have saved like two lines of code. But for Windows it's nice to stop using QueryPerformanceCounter() directly with the complicated math.
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
-
- 21 Jun, 2019 3 commits
-
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
Note that at present I think the only way they would have happened not under-lock is if one of the pthread or syscalls failed, which should never happen. Exceptions thrown by the predicate were already always rethrown under lock. But it doesn't hurt to be safe.
-
- 20 Jun, 2019 1 commit
-
-
Kenton Varda authored
-
- 19 Jun, 2019 3 commits
-
-
Kenton Varda authored
-
Kenton Varda authored
And it turns out that the Windows implementation was returning too early due to rounding error. Fixed.
-
Kenton Varda authored
It turns out GetTickCount64() is only precise to the nearest timeslice, which can be up to 16ms. The imprecision caused test failures.
-
- 18 Jun, 2019 18 commits
-
-
Kenton Varda authored
I think I imagined once upon a time that this would be a convenient way to deal with external interfaces that like to return nullable pointers. However, in practice it is used nowhere in KJ or Cap'n Proto, and it recently hid a bug in my code where I had assigned a `Maybe<T>` from an `Own<T>`. We can introduce a `fromNullablePointer()` helper or something if that turns out to be useful.
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
-
Kenton Varda authored
Consider a capnp streaming type that wraps a kj::AsyncOutputStream. KJ streams require the caller to avoid doing multiple writes at once. Capnp streaming conveniently guarantees only one streaming call will be delivered at a time. This is great because it means the app does not have to do its own queuing of writes. However, the app may want to use a CapabilityServerSet to unwrap the capability and get at the underlying KJ stream to optimize by writing to it directly. However, before it can issue a direct write, it has to wait for all RPC writes to complete. These RPC writes were probably issued by the same caller, before it realized it was talking to a local cap. Unfortunately, it can't just wait for those calls it issued to complete, because streaming flow control may have made them appear to complete long ago, when they're actually still in the server's queue. How does the app make sure that the directly-issued writes don't overlap with RPC writes? We can solve this by making CapabilityServerSet::getLocalServer() delay until all in-flight stream calls are complete before unwrapping. Now, the app can simply make sure that any requests it issued over RPC in the past completed before it starts issuing direct requests.
-
Kenton Varda authored
-
Kenton Varda authored
Also, push harder on the code generator such that `StreamResult` doesn't show up in generated code at all. So now we have `StreamingRequest<Params>` which is like `Request<Params, Results>`, and we have `StreamingCallContext<Params>` which is like `CallContext<Params, Results>`.
-
Kenton Varda authored
-
Kenton Varda authored
There are two things that every capability server must implement: * When a streaming method is delivered, it blocks subsequent calls on the same capability. Although not strictly needed to achieve flow control, this simplifies the implementation of streaming servers -- many would otherwise need to implement such serialization manually. * When a streaming method throws, all subsequent calls also throw the same exception. This is important because exceptions thrown by a streaming call might not actually be delivered to a client, since the client doesn't necessarily wait for the results before making the next call. Again, a streaming server could implement this manually, but almost all streaming servers will likely need it, and this makes things easier.
-
Kenton Varda authored
Note: Apparently, json.capnp had not been added to the bootstrap test, and the checked-in bootstrap had drifted from the source file.
-
Kenton Varda authored
This can be used on a method to indicate that it is used for "streaming", like: write @0 (bytes :Data) -> stream; A "streaming" method is one which is expected to be called many times to transmit an ordered stream of items. For best throughput, it is often necessary to make multiple overlapping calls, so as not to wait for a round trip for every item. However, to avoid excess buffering, it may be necessary to apply backpressure by having the client limit the total number of overlapping calls. This logic is difficult to get right at the application level, so making it a language feature gives us the opportunity to implement it in the RPC layer. We can, however, do it in a way that is backwards-compatible with implementations that don't support it. The above declaration is equivalent to: write @0 (bytes :Data) -> import "/capnp/stream.capnp".StreamResult; RPC implementations that don't explicitly support streaming can thus instead leave it up to the application to handle.
-
Kenton Varda authored
I have this pattern: Maybe<Own<T>> foo; // ... foo = heap<T>(); KJ_ASSERT_NONNULL(foo)->doSomething(); The assertion feels non-type-safe. Now you can do: auto& ref = foo.emplace(heap<T>()); ref.doSomething();
-
Kenton Varda authored
`kj::Quantity<T>` already supported this. I copied from it.
-
Kenton Varda authored
This was failing to chain the promises, and so returning `Promise<Promise<T>>`. The idea here is you can create a PromiseAdapter which eventually produces another promise to chain to. The adapter is finished and should be destroyed at that point, but the final promise should then redirect to the new promise.
-