Make iothread's perform_on_main use std::function

This will allow clients to use lambdas instead of having to
define an out-of-line function
This commit is contained in:
ridiculousfish 2017-01-23 10:37:16 -08:00
parent 7a76efa629
commit e1adc3a6b2
2 changed files with 18 additions and 17 deletions

View file

@ -49,12 +49,10 @@ struct spawn_request_t {
};
struct main_thread_request_t {
int (*handler)(void *) = NULL;
void *context = NULL;
volatile int handler_result = -1;
volatile bool done = false;
std::function<void(void)> func;
main_thread_request_t() {}
main_thread_request_t(std::function<void(void)> &&f) : func(f) {}
// No moving OR copying
// main_thread_requests are always stack allocated, and we deal in pointers to them
@ -305,7 +303,7 @@ static void iothread_service_main_thread_requests(void) {
while (!request_queue.empty()) {
main_thread_request_t *req = request_queue.front();
request_queue.pop();
req->handler_result = req->handler(req->context);
req->func();
req->done = true;
}
@ -342,16 +340,14 @@ static void iothread_service_result_queue() {
}
}
int iothread_perform_on_main_base(int (*handler)(void *), void *context) {
// If this is the main thread, just do it.
void iothread_perform_on_main(std::function<void(void)> &&func) {
if (is_main_thread()) {
return handler(context);
func();
return;
}
// Make a new request. Note we are synchronous, so this can be stack allocated!
main_thread_request_t req;
req.handler = handler;
req.context = context;
main_thread_request_t req(std::move(func));
// Append it. Do not delete the nested scope as it is crucial to the proper functioning of this
// code by virtue of the lock management.
@ -370,10 +366,9 @@ int iothread_perform_on_main_base(int (*handler)(void *), void *context) {
// It would be nice to support checking for cancellation here, but the clients need a
// deterministic way to clean up to avoid leaks
VOMIT_ON_FAILURE(
pthread_cond_wait(&s_main_thread_performer_cond, &s_main_thread_performer_lock));
pthread_cond_wait(&s_main_thread_performer_cond, &s_main_thread_performer_lock));
}
// Ok, the request must now be done.
assert(req.done);
return req.handler_result;
}

View file

@ -2,6 +2,8 @@
#ifndef FISH_IOTHREAD_H
#define FISH_IOTHREAD_H
#include <functional>
/// Runs a command on a thread.
///
/// \param handler The function to execute on a background thread. Accepts an arbitrary context
@ -24,9 +26,6 @@ void iothread_service_completion(void);
/// Waits for all iothreads to terminate.
void iothread_drain_all(void);
/// Performs a function on the main thread, blocking until it completes.
int iothread_perform_on_main_base(int (*handler)(void *), void *context);
/// Helper templates.
template <typename T>
int iothread_perform(int (*handler)(T *), void (*completion)(T *, int), T *context) {
@ -42,9 +41,16 @@ int iothread_perform(int (*handler)(T *), T *context) {
static_cast<void *>(context));
}
/// Performs a function on the main thread, blocking until it completes.
void iothread_perform_on_main(std::function<void(void)> &&func);
template <typename T>
int iothread_perform_on_main(int (*handler)(T *), T *context) {
return iothread_perform_on_main_base((int (*)(void *))handler, (void *)(context));
int result = 0;
iothread_perform_on_main([&result,handler,context](){
result = handler(context);
});
return result;
}
#endif