Mstdlib-1.24.0
|
Typedefs | |
typedef M_bool(* | M_async_write_cb_t) (char *msg, M_uint64 cmd, void *thunk) |
typedef void(* | M_async_thunk_stop_cb_t) (void *thunk) |
typedef void(* | M_async_thunk_destroy_cb_t) (void *thunk) |
typedef struct M_async_writer | M_async_writer_t |
Enumerations | |
enum | M_async_writer_line_end_mode_t { M_ASYNC_WRITER_LINE_END_NATIVE , M_ASYNC_WRITER_LINE_END_UNIX , M_ASYNC_WRITER_LINE_END_WINDOWS } |
Helper class that manages an internal worker thread and message queue for asynchrnous writes.
Used internally in various logging modules.
typedef M_bool(* M_async_write_cb_t) (char *msg, M_uint64 cmd, void *thunk) |
Callback that will be called to write messages.
If your program modifies the "thunk" object outside the callback while the writer is running, you'll need to add your own locks inside the callback to make this reentrant.
The command flag allows you to pass one-off notifications to the callback. These notifications will be processed lazily (i.e., the next time the internal thread tries to write something). Only the next write is affected; after the command flag is used once, it's reset to zero.
It is possible for the write callback to be called with a NULL msg and a non-zero command. This happens when the user sets a command with the force flag set to M_TRUE, but the message queue is empty. In this case, the callback should process the command, but it shouldn't write the empty message.
[in] | msg | message that needs to be written. Can be modified in-place. May be NULL, for command-only calls. |
[in] | thunk | object passed into write_thunk parameter of M_async_writer_create(). |
[in] | cmd | command flag passed into M_async_writer_set_command(). May be 0, if no command sent. |
typedef void(* M_async_thunk_stop_cb_t) (void *thunk) |
typedef void(* M_async_thunk_destroy_cb_t) (void *thunk) |
typedef struct M_async_writer M_async_writer_t |
M_async_writer_t * M_async_writer_create | ( | size_t | max_bytes, |
M_async_write_cb_t | write_cb, | ||
void * | write_thunk, | ||
M_async_thunk_stop_cb_t | stop_cb, | ||
M_async_thunk_destroy_cb_t | destroy_cb, | ||
M_async_writer_line_end_mode_t | mode | ||
) |
Create a writer object.
The writer does not automatically start running, you must call M_async_writer_start().
[in] | max_bytes | maximum bytes that can be queued before messages start getting dropped |
[in] | write_cb | callback that will be called by an internal thread to write messages |
[in] | write_thunk | object that can be used to preserve callback state between writes |
[in] | stop_cb | optional callback that will be called during a stop request |
[in] | destroy_cb | callback that will be used to destroy the thunk when writer is destroyed |
[in] | mode | line-end mode for internally generated error messages |
void M_async_writer_destroy | ( | M_async_writer_t * | writer, |
M_bool | flush | ||
) |
Destroy the writer (non-blocking).
This is a non-blocking operation - the worker thread is commanded to destroy itself, then immediately orphaned. The orphaned thread will still try to delete itself, if it has enough time to do so before the process ends. If the program exits before it has time to do this, it will show up as a memory leak (even though it's not).
This call asks the internal thread to stop running at the next opportunity and then destroy the writer object once stopped. If the internal thread has already been stopped, the object is destroyed by the calling thread.
If you set flush to M_TRUE, the internal thread will output all messages in the queue before it destroys itself. Otherwise, the thread will stop itself right after it finishes the current message it's working on, and will output a message describing the number of dropped messages left in the queue before destroying itself.
If the internal thead is frozen, this is effectively a memory leak - the writer object won't be destroyed until the process exits. But the calling thread won't freeze, so this is probably preferable.
[in] | writer | object we're operating on |
[in] | flush | if M_TRUE, output all messages in queue before destroying |
M_bool M_async_writer_destroy_blocking | ( | M_async_writer_t * | writer, |
M_bool | flush, | ||
M_uint64 | timeout_ms | ||
) |
Destroy the writer (blocking, with timeout).
This call asks the internal thread to stop running at the next opportunity and then destroy the writer object once stopped. If the internal thread has already been stopped, the object is destroyed by the calling thread.
If you set flush to M_TRUE, the internal thread will output all messages in the queue before it destroys itself. Otherwise, the thread will stop itself right after it finishes the current message it's working on, and will output a message describing the number of dropped messages left in the queue before destroying itself.
If the timeout expires before the worker thread is done, the worker thread will be orphaned and control will return to the caller (just like in M_async_writer_destroy()). The orphaned thread will still try to delete itself, if it has enough time to do so before the process ends. If the program exits before it has time to do this, it will show up as a memory leak (even though it's not).
[in] | writer | object we're operating on |
[in] | flush | if M_TRUE, output all messages in queue before destroying |
[in] | timeout_ms | length of time (in milliseconds) to wait until orphaning the worker thread, or 0 for no timeout |
M_bool M_async_writer_start | ( | M_async_writer_t * | writer | ) |
Start writing messages from the queue.
This starts an internal worker thread that pulls messages off of the message queue and writes them.
You can stop the worker thread with M_async_writer_stop() and then restart it with this function, and messages will still be accepted into the message queue the entire time. Start and stop only affect whether messages are being pulled off of the queue and written.
[in] | writer | object we're operating on |
M_bool M_async_writer_is_running | ( | M_async_writer_t * | writer | ) |
Check to see if writer has been started and is accepting messages.
This is non-blocking, we're just checking whether the writer has been started and not stopped. If you need to check if a running writer is frozen or not, use M_async_writer_is_alive().
writer | object we're checking |
M_bool M_async_writer_is_alive | ( | M_async_writer_t * | writer, |
M_uint64 | timeout_ms | ||
) |
Check to see if writer is frozen or not (blocking).
Blocks until either the internal worker thread responds, or the timeout is reached.
If you just want to check if the writer has been started or not, use M_async_writer_is_running() instead, it's non-blocking.
Thread should respond after it finishes with the message that it's currently working on. So, the timeout should be chosen based on the time it takes for the write_cb to execute once (worst case).
[in] | writer | object we're checking |
[in] | timeout_ms | amount of time to wait for thread to respond (in milliseconds) |
void M_async_writer_stop | ( | M_async_writer_t * | writer | ) |
Stop internal worker thread.
This is used when you need to stop the internal worker thread temporarily, and then restart it with a new thread later. Messages are still accepted into the message queue while the writer is stopped, it just doesn't write anything until M_async_writer_start() is called again.
[in] | writer | object we're operating on |
M_bool M_async_writer_set_command | ( | M_async_writer_t * | writer, |
M_uint64 | write_command, | ||
M_bool | force | ||
) |
Set a command flag that will be passed to the write callback the next time it's called.
This can be used to notify the write callback of a condition change (like a request to rotate logs, etc.).
The command will be passed on the next call to the write callback, then reset immediately afterwards.
If multiple calls to this command occur before the next write, the commands will be OR'd together into one value.
You can force the write callback to always be called after the command is set by setting the force flag to M_TRUE. If not set, the command will be processed the next time the internal worker thread pulls a message off the queue (which might not be until the next call to M_async_writer_write(), if the queue is currently empty).
[in] | writer | object we're operating on |
[in] | write_command | flag to pass to write_callback on next write (must be a power of two, or several flags OR'd together) |
[in] | force | if M_TRUE, wakes up writer thread even if message queue is empty. |
M_bool M_async_writer_set_command_block | ( | M_async_writer_t * | writer, |
M_uint64 | write_command | ||
) |
Set a command flag, and block until that command is processed.
Same as M_async_writer_set_command(), except that it blocks until the internal worker thread is done processing the command.
Note that this function always sets the force flag for the command - even if the message queue is empty, the internal worker thread will be awakened and the command will be processed. If the message queue is not empty, the command will be processed when the next message is pulled off of the queue.
[in] | writer | object we're operating on |
[in] | write_command | flag to pass to write_callback on next write (must be a power of two, or several flags OR'd together) |
void M_async_writer_set_max_bytes | ( | M_async_writer_t * | writer, |
size_t | max_bytes | ||
) |
Change the maximum buffer size.
If the writer is running, the new maximum buffer size will not actually be enforced until the next time a message is written to the writer.
[in] | writer | object we're operating on |
[in] | max_bytes | new maximum number of bytes that can be queued before messages start getting dropped |
M_bool M_async_writer_write | ( | M_async_writer_t * | writer, |
const char * | msg | ||
) |
Write a message to the writer (non-blocking).
The message will be added to a work queue, to be passed later to write_callback by an internal worker thread.
If the message can't be added (empty message, message itself is larger than queue, alloc error, or writer is in the middle of a flush-stop) the message is dropped without modifying the internal queue.
If the queue doesn't have enough empty space to fit the message, messages in the queue are dropped until there is enough room. The oldest message is dropped first, then the next oldest, and so on, until there's enough room in the queue to add the new message.
Note that an async writer will still accept messages passed with this function when stopped - it will just add them to the message queue, and wait until the writer is started again to write them.
[in] | writer | object we're operating on |
[in] | msg | message to add to write queue |
void * M_async_writer_get_thunk | ( | M_async_writer_t * | writer | ) |
Return the internal writer callback thunk.
[in] | writer | object we're operating on |
const char * M_async_writer_get_line_end | ( | M_async_writer_t * | writer | ) |
Return the line ending string in use by the writer.
[in] | writer | object we're operating on |