Use ipc queue for all messages (#3585)

I was able to reproduce #3579 in Linux by running:
`sudo sysctl net.core.wmem_default=10000`

If a subscription message was too big to be sent at once, it was
possible to break a client by sending a reply to an other message sent
by the client. Eg:
- Write 8192 out of 11612 bytes of a workspace event.
- Blockingly write the reply to a workspace change message.
- Write the rest 3420 bytes of the workspace event.

This commit fixes this by utilizing the ipc queue for all types of
writes.

ipc_receive_message can only be called from a callback started in
ipc_new_client. This callback uses the same file descriptor with the
client also created in ipc_new_client. When the client is deleted, the
read callback is now also stopped. Thus, we can assume that whenever
ipc_receive_message is called, the corresponding client should still
exist.

- ipc_client now contains pointers to both write and read watchers. When
freed, a client will stop both of them.
- IPC_HANDLERs now work with ipc_clients instead of fds.

Fixes #3579.
This commit is contained in:
Orestis
2019-01-12 14:13:03 +02:00
committed by Michael Stapelberg
parent cf375927f0
commit 54e7a31568
2 changed files with 99 additions and 133 deletions

View File

@ -35,7 +35,8 @@ typedef struct ipc_client {
* event has been sent by i3. */
bool first_tick_sent;
struct ev_io *callback;
struct ev_io *read_callback;
struct ev_io *write_callback;
struct ev_timer *timeout;
uint8_t *buffer;
size_t buffer_size;
@ -54,12 +55,12 @@ typedef struct ipc_client {
* message_type is the type of the message as the sender specified it.
*
*/
typedef void (*handler_t)(int, uint8_t *, int, uint32_t, uint32_t);
typedef void (*handler_t)(ipc_client *, uint8_t *, int, uint32_t, uint32_t);
/* Macro to declare a callback */
#define IPC_HANDLER(name) \
static void handle_##name(int fd, uint8_t *message, \
int size, uint32_t message_size, \
#define IPC_HANDLER(name) \
static void handle_##name(ipc_client *client, uint8_t *message, \
int size, uint32_t message_size, \
uint32_t message_type)
/**