2 /* Register an fd which produces wake events with
4 * Whenever the fd is readable, we block suspend,
5 * call the handler, then allow suspend.
6 * Meanwhile we open a socket to the event daemon passing
8 * At a lower priority, when we read 'S' from the daemon we reply
11 * Copyright (C) 2011 Neil Brown <neilb@suse.de>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <sys/socket.h>
41 void (*fn)(int,short,void*);
45 static void wakeup_call(int fd, short ev, void *data)
47 /* A (potential) wakeup event can be read from this fd.
48 * We won't go to sleep because we haven't replied to
49 * 'S' yet as that is handle with a lower priority.
51 struct han *han = data;
52 han->fn(fd, ev, han->data);
55 static void wakeup_sock(int fd, short ev, void *data)
58 struct han *han = data;
59 int n = read(fd, &buf, 1);
61 if (n < 0 && errno == EAGAIN)
64 /* How do I signal an error ?*/
69 /* As we are at a lower priority (higher number)
70 * than the main event, we must have handled everything
75 static void send_fd(int sock, int fd)
77 struct msghdr msg = {0};
81 char buf[CMSG_SPACE(sizeof myfds)];
84 msg.msg_control = buf;
85 msg.msg_controllen = sizeof buf;
86 cmsg = CMSG_FIRSTHDR(&msg);
87 cmsg->cmsg_level = SOL_SOCKET;
88 cmsg->cmsg_type = SCM_RIGHTS;
89 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
90 fdptr = (int*)CMSG_DATA(cmsg);
92 msg.msg_controllen = cmsg->cmsg_len;
97 sendmsg(sock, &msg, 0);
100 struct event *wake_set(int fd, void(*fn)(int,short,void*), void *data, int prio)
102 struct sockaddr_un addr;
103 struct han *h = malloc(sizeof(*h));
110 h->disable = suspend_open();
111 h->sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
112 if (h->sock < 0 || h->disable < 0)
114 addr.sun_family = AF_UNIX;
115 strcpy(addr.sun_path, "/run/suspend/registration");
116 if (connect(h->sock, (struct sockaddr*)&addr, sizeof(addr)) != 0)
119 fcntl(h->sock, F_SETFL, fcntl(h->sock, F_GETFL, 0) | O_NONBLOCK);
121 send_fd(h->sock, fd);
123 event_set(&h->ev, fd, EV_READ|EV_PERSIST, wakeup_call, h);
124 event_set(&h->sev, h->sock, EV_READ|EV_PERSIST, wakeup_sock, h);
125 event_priority_set(&h->ev, prio);
126 event_priority_set(&h->sev, prio+1);
127 event_add(&h->ev, NULL);
128 event_add(&h->sev, NULL);
133 suspend_close(h->disable);
140 void wake_destroy(struct event *ev)
142 struct han *h = (struct han *)ev;
146 suspend_close(h->disable);