/* Copyright (c) 2009 by Juliusz Chroboczek Copyright (c) 2013 by Yoran Heling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* This is a thread pool implementation for convenient use with libev[1]. It * mimics the libev and libeio[2] API to some extent. The core thread pool code * is based on the threadpool library[3] by Juliusz Chroboczek. If you're * looking for a generic thread pool that doesn't rely on libev, use that. * * 1. http://software.schmorp.de/pkg/libev * 2. http://software.schmorp.de/pkg/libeio * 3. https://github.com/jech/threadpool * * TODO: * - Cancellation? * - Allow done_func = NULL? (Implies auto-free()-work-object-when-done) */ #ifndef EVTP_H #define EVTP_H #include #include typedef struct evtp_t evtp_t; /* Opaque */ typedef struct evtp_work_t evtp_work_t; typedef void (*evtp_func_t)(evtp_work_t *); struct evtp_work_t { /* Public */ void *data; /* Private */ evtp_func_t work_func; evtp_func_t done_func; evtp_work_t *next; }; /* Create a new thread pool. May return NULL if malloc() fails. * * The thread pool object itself does not hold a reference on the ev loop. Each * evtp_work_t object in the queue, however, does. This way, ev_run() may quit * even when a thread pool object is alive, but it will never quit as long * there is still work to do. */ evtp_t *evtp_create(EV_P_ int maxthreads); /* Submit work to the thread pool. Returns -1 if pthread_create() failed and we * have no threads running (fatal), 0 if pthread_create() failed but we still * have a worker thread (recoverable), or 1 if everything went fine. * * work_func() will be called in a worker thread. A short while after * work_func() returns, done_func() will be called in the thread that runs * ev_run() on the ev loop given to evtp_create(). * * The *work object must remain valid until done_func() is called. */ int evtp_submit(evtp_work_t *work, evtp_t *evtp, evtp_func_t work_func, evtp_func_t done_func); /* Convenience function that allocates a new work object for you. You must * still free() the object in the done_func! */ static inline evtp_work_t *evtp_submit_new(evtp_t *evtp, evtp_func_t work_func, evtp_func_t done_func, void *data) { evtp_work_t *w = calloc(1, sizeof(evtp_work_t)); w->data = data; if(evtp_submit(w, evtp, work_func, done_func) < 0) { free(w); w = NULL; } return w; } /* Cause a thread pool to die. Returns whenever there is new stuff in the callback queue, or immediately if canblock is false. Returns true when the thread pool is dead. */ int evtp_die(evtp_t *threadpool, int canblock); /* Destroy a thread pool. Does nothing and returns -1 if the pool is not dead. */ int evtp_destroy(evtp_t *threadpool); #endif /* vim: set noet sw=4 ts=4: */