#ifndef EINA_THREAD_QUEUE_H_ #define EINA_THREAD_QUEUE_H_ /** * @addtogroup Eina_Thread_Queue_Group Thread Queue Group * @ingroup Eina * * @brief These functions provide simple zero-copy message queues for threads * * @{ * * @since 1.11 */ /** * @typedef Eina_Thread_Queue * * This is a uni-directional zero-copy thread message queue specifically * designed with the idea of sending large volumes of messages with no * copies from one thread to another (or from/to the mainloop). The idea * is that a thread queue is created and then one or more threads send * messages in one end and fetch messages off the other end. If you set a * parent message queue to 1 or more queues, then this parent will wake up * with a sub queue message, indicating which child queue woke up. This can * be used to implement the ability to listen to multiple queues at once. * * @since 1.11 */ typedef struct _Eina_Thread_Queue Eina_Thread_Queue; /** * @typedef Eina_Thread_Queue_Msg * * This is the minimal header of every message to be put into an Eina * Thread Queue. Every message has at least this header at the start of the * message data, with payload following. You would put this structure as * the first struct member of every message type you have, like * Eina_Thread_Queue_Msg_Sub does. Messages are always 8 byte aligned within * message memory to ensure alignment of all types. * * @since 1.11 */ typedef struct _Eina_Thread_Queue_Msg Eina_Thread_Queue_Msg; /** * @typedef Eina_Thread_Queue_Msg_Sub * * This is a special message type for Eina Thread Queues that have child * queues. This is the only Message type for a parent message queue and * it indicates which child queue was woken up with a new message to read. * When this message is retrieved, the caller should then also fetch the * message from the indicated child queue too. * * @since 1.11 */ typedef struct _Eina_Thread_Queue_Msg_Sub Eina_Thread_Queue_Msg_Sub; struct _Eina_Thread_Queue_Msg { int size; /*< The size of the message in bytes, including this header */ }; struct _Eina_Thread_Queue_Msg_Sub { Eina_Thread_Queue_Msg head; /*< Standard header on all messages */ Eina_Thread_Queue *queue; /*< The child queue that woke up and needs a message fetched from it */ }; /** * @brief Creates a new thread queue. * * @return A valid new thread queue, or NULL on failure * * @since 1.11 */ EAPI Eina_Thread_Queue * eina_thread_queue_new(void); /** * @brief Frees a thread queue. * * This frees a thread queue. It must no longer be in use by anything waiting * on messages or sending them. Any pending messages will be freed without * being processed by a listener. * * @param[in] thq The thread queue to free * * @since 1.11 */ EAPI void eina_thread_queue_free(Eina_Thread_Queue *thq) EINA_ARG_NONNULL(1); /** * @brief Allocates a message to send down a thread queue. * * @param[in,out] thq The thread queue to allocate the message on * @param[in] size The size, in bytes, of the message, including standard header * @param[out] allocref A pointer to store a general reference handle for the message * @return A pointer to the message data to fill in * * This allocates space for a new message on the message queue, but does not * actually trigger the send. For that you will need to call * eina_thread_queue_send_done() to complete the send and trigger the other * side. Every message must at least be a Eina_Thread_Queue_Msg in size and * have this structure as the first member (first N bytes) of the message. * * @since 1.11 */ EAPI void * eina_thread_queue_send(Eina_Thread_Queue *thq, int size, void **allocref) EINA_ARG_NONNULL(1, 3); /** * @brief Finishes sending the allocated message. * * @param[in,out] thq The thread queue the message was placed on * @param[in,out] allocref The allocref returned by eina_thread_queue_send() * * This completes the send and triggers the thread queue to wake up any * listeners. * * @since 1.11 */ EAPI void eina_thread_queue_send_done(Eina_Thread_Queue *thq, void *allocref) EINA_ARG_NONNULL(1, 2); /** * @brief Fetches a message from a thread queue. * * @param[in,out] thq The thread queue to fetch the message from * @param[out] allocref A pointer to store a general reference handle for the message * @return A pointer to the message data * * This will fetch the next message to read from the thread queue and return * a pointer to it. The message is guaranteed to have an initial * Eina_Thread_Queue_Msg member that will indicate size of the message as * a whole. This function will wait, if no messages are available to read * and block until a new message comes in, then return. When the message is * finished with, the caller must use eina_thread_queue_wait_done() to indicate * they are done. * * @since 1.11 */ EAPI void * eina_thread_queue_wait(Eina_Thread_Queue *thq, void **allocref) EINA_ARG_NONNULL(1, 2); /** * @brief Finishes fetching a message from a thread queue. * * @param[in,out] thq The thread queue the message was fetched from * @param[in,out] allocref The allocref returned by eina_thread_queue_wait() * * This should be used after eina_thread_queue_wait() or * eina_thread_queue_poll() to indicate the caller is done with the message. * * @since 1.11 */ EAPI void eina_thread_queue_wait_done(Eina_Thread_Queue *thq, void *allocref) EINA_ARG_NONNULL(1, 2); /** * @brief Fetches a message from a thread queue, but return immediately if there is none with NULL. * * @param[in,out] thq The thread queue to fetch the message from * @param[out] allocref A pointer to store a general reference handle for the message * @return A pointer to the message data * * This is the same as eina_thread_queue_wait(), but if no messages are * available for reading, it immediately returns NULL to the caller, without * waiting for a new message to arrive. * * @see eina_thread_queue_wait() * * @since 1.11 */ EAPI void * eina_thread_queue_poll(Eina_Thread_Queue *thq, void **allocref) EINA_ARG_NONNULL(1, 2); /** * @brief Gets the number of messages on a queue as yet unfetched. * * @param[in] thq The thread queue to query for pending count * @return The number of messages waiting to be fetched * * This returns the number of messages waiting to be fetched with * eina_thread_queue_wait() or eina_thread_queue_poll(). * * @since 1.11 */ EAPI int eina_thread_queue_pending_get(const Eina_Thread_Queue *thq) EINA_ARG_NONNULL(1); /** * @brief Sets the parent of a thread queue (make this one a child). * * @param[in,out] thq The thread queue to alter the parent of * @param[in] thq_parent The new parent to set * * This sets the parent queue where messages will be reported to. This is * how you can listen to multiple queues at once - set multiple queues to * have the same parent and then just wait on that one parent. This should * be done before any messages are read from or written to the queue. To unset * a parent, just set the parent to NULL. * * @since 1.11 */ EAPI void eina_thread_queue_parent_set(Eina_Thread_Queue *thq, Eina_Thread_Queue *thq_parent) EINA_ARG_NONNULL(1); /** * @brief Gets the parent of a thread queue. * * @param[in] thq The thread queue to get the parent of * @return The parent thread queue * * This gets the parent set by eina_thread_queue_parent_get(). If no parent * is set, NULL is returned. * * @see eina_thread_queue_parent_set() * * @since 1.11 */ EAPI Eina_Thread_Queue * eina_thread_queue_parent_get(const Eina_Thread_Queue *thq) EINA_ARG_NONNULL(1); /** * @brief Sets a file descriptor to write a byte to on a message send. * * @param[in,out] thq The thread queue to set the file descriptor of * @param[in] fd The fd to set, or -1 to unset it * * This sets a file descriptor to write to when a message is written to the * thread queue. This can be used to glue a thread queue to something like * an Ecore_Pipe that can wake up the mainloop and call a callback whenever * data is available on the pipe. The number of bytes available will be * the number of messages to fetch from the associated thread queue. * * You should set this up before anything writes to or reads from this * thread queue. * * @since 1.11 */ EAPI void eina_thread_queue_fd_set(Eina_Thread_Queue *thq, int fd) EINA_ARG_NONNULL(1); /** * @brief Gets the file descriptor written to on message sends. * * @param[in] thq The thread queue to get the file descriptor of * @return The file descriptor set (or -1 if none is set). * * This returns the file descriptor set by eina_thread_queue_fd_set() and * by default returns -1 (no fd set). * * @see eina_thread_queue_fd_set() * * @since 1.11 */ EAPI int eina_thread_queue_fd_get(const Eina_Thread_Queue *thq) EINA_ARG_NONNULL(1); /** * @} */ #endif