2016-05-02 04:01:00 +00:00
|
|
|
// Handles IO that may hang.
|
2011-12-27 05:21:12 +00:00
|
|
|
#ifndef FISH_IOTHREAD_H
|
|
|
|
#define FISH_IOTHREAD_H
|
|
|
|
|
Introduce topic monitoring
topic_monitor allows for querying changes posted to one or more topics,
initially sigchld. This will eventually replace the waitpid logic in
process_mark_finished_children().
Comment from the new header:
Topic monitoring support. Topics are conceptually "a thing that can
happen." For example, delivery of a SIGINT, a child process exits, etc. It
is possible to post to a topic, which means that that thing happened.
Associated with each topic is a current generation, which is a 64 bit
value. When you query a topic, you get back a generation. If on the next
query the generation has increased, then it indicates someone posted to
the topic.
For example, if you are monitoring a child process, you can query the
sigchld topic. If it has increased since your last query, it is possible
that your child process has exited.
Topic postings may be coalesced. That is there may be two posts to a given
topic, yet the generation only increases by 1. The only guarantee is that
after a topic post, the current generation value is larger than any value
previously queried.
Tying this all together is the topic_monitor_t. This provides the current
topic generations, and also provides the ability to perform a blocking
wait for any topic to change in a particular topic set. This is the real
power of topics: you can wait for a sigchld signal OR a thread exit.
2019-02-02 23:39:04 +00:00
|
|
|
#include <pthread.h>
|
2017-01-23 18:37:16 +00:00
|
|
|
#include <functional>
|
2017-02-11 02:47:02 +00:00
|
|
|
#include <type_traits>
|
2017-01-23 18:37:16 +00:00
|
|
|
|
2016-05-02 04:01:00 +00:00
|
|
|
/// Runs a command on a thread.
|
|
|
|
///
|
|
|
|
/// \param handler The function to execute on a background thread. Accepts an arbitrary context
|
|
|
|
/// pointer, and returns an int, which is passed to the completionCallback.
|
|
|
|
/// \param completionCallback The function to execute on the main thread once the background thread
|
|
|
|
/// is complete. Accepts an int (the return value of handler) and the context.
|
|
|
|
/// \param context A arbitary context pointer to pass to the handler and completion callback.
|
|
|
|
/// \return A sequence number, currently not very useful.
|
|
|
|
int iothread_perform_base(int (*handler)(void *), void (*completionCallback)(void *, int),
|
|
|
|
void *context);
|
|
|
|
|
|
|
|
/// Gets the fd on which to listen for completion callbacks.
|
|
|
|
///
|
|
|
|
/// \return A file descriptor on which to listen for completion callbacks.
|
2011-12-27 05:21:12 +00:00
|
|
|
int iothread_port(void);
|
|
|
|
|
2016-05-02 04:01:00 +00:00
|
|
|
/// Services one iothread competion callback.
|
2011-12-27 05:21:12 +00:00
|
|
|
void iothread_service_completion(void);
|
|
|
|
|
2016-05-02 04:01:00 +00:00
|
|
|
/// Waits for all iothreads to terminate.
|
2012-02-28 03:46:15 +00:00
|
|
|
void iothread_drain_all(void);
|
|
|
|
|
2017-01-24 17:30:30 +00:00
|
|
|
// Internal implementation
|
2017-01-27 04:00:43 +00:00
|
|
|
int iothread_perform_impl(std::function<void(void)> &&func, std::function<void(void)> &&completion);
|
2017-01-23 19:35:22 +00:00
|
|
|
|
2017-01-24 17:30:30 +00:00
|
|
|
// Template helpers
|
2017-01-26 17:33:03 +00:00
|
|
|
// This is the glue part of the handler-completion handoff
|
|
|
|
// In general we can just allocate an object, move the result of the handler into it,
|
|
|
|
// and then call the completion with that object. However if our type is void,
|
|
|
|
// this won't work (new void() fails!). So we have to use this template.
|
|
|
|
// The type T is the return type of HANDLER and the argument to COMPLETION
|
2017-01-27 04:00:43 +00:00
|
|
|
template <typename T>
|
2017-01-24 17:30:30 +00:00
|
|
|
struct _iothread_trampoline {
|
2017-01-27 04:00:43 +00:00
|
|
|
template <typename HANDLER, typename COMPLETION>
|
2017-01-24 17:30:30 +00:00
|
|
|
static int perform(const HANDLER &handler, const COMPLETION &completion) {
|
2017-01-27 04:00:43 +00:00
|
|
|
T *result = new T(); // TODO: placement new?
|
|
|
|
return iothread_perform_impl([=]() { *result = handler(); },
|
|
|
|
[=]() {
|
|
|
|
completion(std::move(*result));
|
|
|
|
delete result;
|
|
|
|
});
|
2017-01-24 17:30:30 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Void specialization
|
2017-01-27 04:00:43 +00:00
|
|
|
template <>
|
2017-01-24 17:30:30 +00:00
|
|
|
struct _iothread_trampoline<void> {
|
2017-01-27 04:00:43 +00:00
|
|
|
template <typename HANDLER, typename COMPLETION>
|
2017-01-24 17:30:30 +00:00
|
|
|
static int perform(const HANDLER &handler, const COMPLETION &completion) {
|
|
|
|
return iothread_perform_impl(handler, completion);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// iothread_perform invokes a handler on a background thread, and then a completion function
|
|
|
|
// on the main thread. The value returned from the handler is passed to the completion.
|
2017-01-26 17:33:03 +00:00
|
|
|
// In other words, this is like COMPLETION(HANDLER()) except the handler part is invoked
|
|
|
|
// on a background thread.
|
2017-01-27 04:00:43 +00:00
|
|
|
template <typename HANDLER, typename COMPLETION>
|
2017-01-24 17:30:30 +00:00
|
|
|
int iothread_perform(const HANDLER &handler, const COMPLETION &completion) {
|
|
|
|
return _iothread_trampoline<decltype(handler())>::perform(handler, completion);
|
|
|
|
}
|
|
|
|
|
|
|
|
// variant of iothread_perform without a completion handler
|
|
|
|
inline int iothread_perform(std::function<void(void)> &&func) {
|
2019-02-01 09:04:14 +00:00
|
|
|
return iothread_perform_impl(std::move(func), {});
|
2017-01-23 19:35:22 +00:00
|
|
|
}
|
|
|
|
|
2017-01-23 18:37:16 +00:00
|
|
|
/// Performs a function on the main thread, blocking until it completes.
|
|
|
|
void iothread_perform_on_main(std::function<void(void)> &&func);
|
|
|
|
|
2019-02-01 09:04:14 +00:00
|
|
|
/// Creates a pthread, manipulating the signal mask so that the thread receives no signals.
|
|
|
|
/// The pthread runs \p func.
|
|
|
|
/// \returns true on success, false on failure.
|
|
|
|
bool make_pthread(pthread_t *result, void *(*func)(void *), void *param);
|
|
|
|
bool make_pthread(pthread_t *result, std::function<void(void)> &&func);
|
|
|
|
|
2019-05-29 19:33:44 +00:00
|
|
|
/// \returns a thread ID for this thread.
|
|
|
|
/// Thread IDs are never repeated.
|
|
|
|
uint64_t thread_id();
|
|
|
|
|
2011-12-27 05:21:12 +00:00
|
|
|
#endif
|