CI: Various updates to buildAsterisk.sh
[asterisk/asterisk.git] / main / alertpipe.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2017, Sean Bright
5  *
6  * Sean Bright <sean.bright@gmail.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Alert Pipe API
22  *
23  * \author Sean Bright
24  */
25
26 #include "asterisk.h"
27
28 #include <unistd.h>
29 #include <fcntl.h>
30
31 #ifdef HAVE_EVENTFD
32 # include <sys/eventfd.h>
33 #endif
34
35 #include "asterisk/alertpipe.h"
36 #include "asterisk/logger.h"
37
38 int ast_alertpipe_init(int alert_pipe[2])
39 {
40 #ifdef HAVE_EVENTFD
41
42         int fd = eventfd(0, EFD_NONBLOCK | EFD_SEMAPHORE);
43         if (fd > -1) {
44                 alert_pipe[0] = alert_pipe[1] = fd;
45                 return 0;
46         }
47
48         ast_log(LOG_WARNING, "Failed to create alert pipe with eventfd(), falling back to pipe(): %s\n",
49                 strerror(errno));
50         ast_alertpipe_clear(alert_pipe);
51
52 #endif
53
54         if (pipe(alert_pipe)) {
55                 ast_log(LOG_WARNING, "Failed to create alert pipe: %s\n", strerror(errno));
56                 return -1;
57         } else {
58                 if (ast_fd_set_flags(alert_pipe[0], O_NONBLOCK)
59                    || ast_fd_set_flags(alert_pipe[1], O_NONBLOCK)) {
60                         ast_alertpipe_close(alert_pipe);
61                         return -1;
62                 }
63         }
64
65         return 0;
66 }
67
68 void ast_alertpipe_close(int alert_pipe[2])
69 {
70 #ifdef HAVE_EVENTFD
71
72         if (alert_pipe[0] == alert_pipe[1]) {
73                 if (alert_pipe[0] > -1) {
74                         close(alert_pipe[0]);
75                         ast_alertpipe_clear(alert_pipe);
76                 }
77                 return;
78         }
79
80 #endif
81
82         if (alert_pipe[0] > -1) {
83                 close(alert_pipe[0]);
84         }
85         if (alert_pipe[1] > -1) {
86                 close(alert_pipe[1]);
87         }
88         ast_alertpipe_clear(alert_pipe);
89 }
90
91 ast_alert_status_t ast_alertpipe_read(int alert_pipe[2])
92 {
93         uint64_t tmp;
94
95         if (!ast_alertpipe_readable(alert_pipe)) {
96                 return AST_ALERT_NOT_READABLE;
97         }
98
99         if (read(alert_pipe[0], &tmp, sizeof(tmp)) < 0) {
100                 if (errno != EINTR && errno != EAGAIN) {
101                         ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
102                         return AST_ALERT_READ_FAIL;
103                 }
104         }
105
106         return AST_ALERT_READ_SUCCESS;
107 }
108
109 ssize_t ast_alertpipe_write(int alert_pipe[2])
110 {
111         uint64_t tmp = 1;
112
113         if (!ast_alertpipe_writable(alert_pipe)) {
114                 errno = EBADF;
115                 return 0;
116         }
117
118         /* preset errno in case returned size does not match */
119         errno = EPIPE;
120         return write(alert_pipe[1], &tmp, sizeof(tmp)) != sizeof(tmp);
121 }
122
123 ast_alert_status_t ast_alertpipe_flush(int alert_pipe[2])
124 {
125         int bytes_read;
126         uint64_t tmp[16];
127
128         if (!ast_alertpipe_readable(alert_pipe)) {
129                 return AST_ALERT_NOT_READABLE;
130         }
131
132         /* Read the alertpipe until it is exhausted. */
133         for (;;) {
134                 bytes_read = read(alert_pipe[0], tmp, sizeof(tmp));
135                 if (bytes_read < 0) {
136                         if (errno == EINTR) {
137                                 continue;
138                         }
139                         if (errno == EAGAIN || errno == EWOULDBLOCK) {
140                                 /*
141                                  * Would block so nothing left to read.
142                                  * This is the normal loop exit.
143                                  */
144                                 break;
145                         }
146                         ast_log(LOG_WARNING, "read() failed flushing alertpipe: %s\n",
147                                 strerror(errno));
148                         return AST_ALERT_READ_FAIL;
149                 }
150                 if (!bytes_read) {
151                         /* Read nothing so we are done */
152                         break;
153                 }
154         }
155
156         return AST_ALERT_READ_SUCCESS;
157 }