summaryrefslogtreecommitdiff
path: root/cras/src/server/cras_main_message.c
blob: b88e4000774e4b9593b4dbfb9abcc9aab7b3d327 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>

#include "cras_main_message.h"
#include "cras_system_state.h"
#include "cras_util.h"

/* Callback to handle specific type of main thread message. */
struct cras_main_msg_callback {
	enum CRAS_MAIN_MESSAGE_TYPE type;
	cras_message_callback callback;
	void *callback_data;
	struct cras_main_msg_callback *prev, *next;
};

static int main_msg_fds[2];
static struct cras_main_msg_callback *main_msg_callbacks;

int cras_main_message_add_handler(enum CRAS_MAIN_MESSAGE_TYPE type,
				  cras_message_callback callback,
				  void *callback_data)
{
	struct cras_main_msg_callback *msg_cb;

	DL_FOREACH (main_msg_callbacks, msg_cb) {
		if (msg_cb->type == type) {
			syslog(LOG_ERR, "Main message type %u already exists",
			       type);
			return -EEXIST;
		}
	}

	msg_cb = (struct cras_main_msg_callback *)calloc(1, sizeof(*msg_cb));
	msg_cb->type = type;
	msg_cb->callback = callback;
	msg_cb->callback_data = callback_data;

	DL_APPEND(main_msg_callbacks, msg_cb);
	return 0;
}

int cras_main_message_send(struct cras_main_message *msg)
{
	int err;

	err = write(main_msg_fds[1], msg, msg->length);
	if (err < 0) {
		syslog(LOG_ERR, "Failed to send main message, type %u",
		       msg->type);
		return err;
	}
	return 0;
}

static int read_main_message(int msg_fd, uint8_t *buf, size_t max_len)
{
	int to_read, nread, rc;
	struct cras_main_message *msg = (struct cras_main_message *)buf;

	nread = read(msg_fd, buf, sizeof(msg->length));
	if (nread < 0)
		return nread;
	if (msg->length > max_len)
		return -ENOMEM;

	to_read = msg->length - nread;
	rc = read(msg_fd, &buf[0] + nread, to_read);
	if (rc < 0)
		return rc;
	return 0;
}

static void handle_main_messages(void *arg, int revents)
{
	uint8_t buf[256];
	int rc;
	struct cras_main_msg_callback *main_msg_cb;
	struct cras_main_message *msg = (struct cras_main_message *)buf;

	rc = read_main_message(main_msg_fds[0], buf, sizeof(buf));
	if (rc < 0) {
		syslog(LOG_ERR, "Failed to read main message");
		return;
	}

	DL_FOREACH (main_msg_callbacks, main_msg_cb) {
		if (main_msg_cb->type == msg->type) {
			main_msg_cb->callback(msg, main_msg_cb->callback_data);
			break;
		}
	}
}

void cras_main_message_init()
{
	int rc;

	rc = pipe(main_msg_fds);
	if (rc < 0) {
		syslog(LOG_ERR, "Fatal: main message init");
		exit(-ENOMEM);
	}

	/* When full it's preferred to get error instead of blocked. */
	cras_make_fd_nonblocking(main_msg_fds[0]);
	cras_make_fd_nonblocking(main_msg_fds[1]);

	cras_system_add_select_fd(main_msg_fds[0], handle_main_messages, NULL,
				  POLLIN);
}