1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #define _GNU_SOURCE /* For ppoll() */ 7 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <pthread.h> 11 #include <poll.h> 12 #include <sched.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <syslog.h> 16 #include <sys/param.h> 17 #include <sys/resource.h> 18 #include <sys/socket.h> 19 #include <sys/syscall.h> 20 #include <sys/types.h> 21 #include <unistd.h> 22 23 #include "cras_util.h" 24 25 int cras_set_rt_scheduling(int rt_lim) 26 { 27 struct rlimit rl; 28 29 rl.rlim_cur = rl.rlim_max = rt_lim; 30 31 if (setrlimit(RLIMIT_RTPRIO, &rl) < 0) { 32 syslog(LOG_WARNING, "setrlimit %u failed: %d\n", 33 (unsigned) rt_lim, errno); 34 return -EACCES; 35 } 36 return 0; 37 } 38 39 int cras_set_thread_priority(int priority) 40 { 41 struct sched_param sched_param; 42 int err; 43 44 memset(&sched_param, 0, sizeof(sched_param)); 45 sched_param.sched_priority = priority; 46 47 err = pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param); 48 if (err) 49 syslog(LOG_WARNING, 50 "Failed to set thread sched params to priority %d" 51 ", rc: %d\n", priority, err); 52 53 return err; 54 } 55 56 int cras_set_nice_level(int nice) 57 { 58 int rc; 59 60 /* Linux isn't posix compliant with setpriority(2), it will set a thread 61 * priority if it is passed a tid, not affecting the rest of the threads 62 * in the process. Setting this priority will only succeed if the user 63 * has been granted permission to adjust nice values on the system. 64 */ 65 rc = setpriority(PRIO_PROCESS, syscall(__NR_gettid), nice); 66 if (rc) 67 syslog(LOG_WARNING, "Failed to set nice to %d, rc: %d", 68 nice, rc); 69 70 return rc; 71 } 72 73 int cras_make_fd_nonblocking(int fd) 74 { 75 int fl; 76 77 fl = fcntl(fd, F_GETFL); 78 if (fl < 0) 79 return fl; 80 if (fl & O_NONBLOCK) 81 return 0; 82 return fcntl(fd, F_SETFL, fl | O_NONBLOCK); 83 } 84 85 int cras_make_fd_blocking(int fd) 86 { 87 int fl; 88 89 fl = fcntl(fd, F_GETFL); 90 if (fl < 0) 91 return fl; 92 if ((~fl) & O_NONBLOCK) 93 return 0; 94 return fcntl(fd, F_SETFL, fl & ~O_NONBLOCK); 95 } 96 97 int cras_send_with_fds(int sockfd, const void *buf, size_t len, int *fd, 98 unsigned int num_fds) 99 { 100 struct msghdr msg = {0}; 101 struct iovec iov; 102 struct cmsghdr *cmsg; 103 char *control; 104 const unsigned int control_size = CMSG_SPACE(sizeof(*fd) * num_fds); 105 int rc; 106 107 control = calloc(control_size, 1); 108 109 msg.msg_iov = &iov; 110 msg.msg_iovlen = 1; 111 iov.iov_base = (void *)buf; 112 iov.iov_len = len; 113 114 msg.msg_control = control; 115 msg.msg_controllen = control_size; 116 117 cmsg = CMSG_FIRSTHDR(&msg); 118 cmsg->cmsg_level = SOL_SOCKET; 119 cmsg->cmsg_type = SCM_RIGHTS; 120 cmsg->cmsg_len = CMSG_LEN(sizeof(*fd) * num_fds); 121 memcpy(CMSG_DATA(cmsg), fd, sizeof(*fd) * num_fds); 122 123 rc = sendmsg(sockfd, &msg, 0); 124 free(control); 125 return rc; 126 } 127 128 int cras_recv_with_fds(int sockfd, void *buf, size_t len, int *fd, 129 unsigned int *num_fds) 130 { 131 struct msghdr msg = {0}; 132 struct iovec iov; 133 struct cmsghdr *cmsg; 134 char *control; 135 const unsigned int control_size = CMSG_SPACE(sizeof(*fd) * *num_fds); 136 int rc; 137 int i; 138 139 control = calloc(control_size, 1); 140 141 for (i = 0; i < *num_fds; i++) 142 fd[i] = -1; 143 144 msg.msg_iov = &iov; 145 msg.msg_iovlen = 1; 146 iov.iov_base = buf; 147 iov.iov_len = len; 148 msg.msg_control = control; 149 msg.msg_controllen = control_size; 150 151 rc = recvmsg(sockfd, &msg, 0); 152 if (rc < 0) { 153 rc = -errno; 154 goto exit; 155 } 156 157 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 158 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 159 if (cmsg->cmsg_level == SOL_SOCKET 160 && cmsg->cmsg_type == SCM_RIGHTS) { 161 size_t fd_size = cmsg->cmsg_len - sizeof(*cmsg); 162 *num_fds = MIN(*num_fds, fd_size / sizeof(*fd)); 163 memcpy(fd, CMSG_DATA(cmsg), *num_fds * sizeof(*fd)); 164 break; 165 } 166 } 167 168 exit: 169 free(control); 170 return rc; 171 } 172 173 int cras_poll(struct pollfd *fds, nfds_t nfds, struct timespec *timeout, 174 const sigset_t *sigmask) 175 { 176 struct timespec now; 177 struct timespec future; 178 struct pollfd *fd = fds; 179 nfds_t i; 180 int rc = 0; 181 182 if (timeout) { 183 /* Treat a negative timeout as valid (but timed-out) since 184 * this function could update timeout to have negative tv_sec 185 * or tv_nsec. */ 186 if (timeout->tv_sec < 0 || timeout->tv_nsec < 0) 187 return -ETIMEDOUT; 188 rc = clock_gettime(CLOCK_MONOTONIC_RAW, &future); 189 if (rc < 0) 190 return -errno; 191 add_timespecs(&future, timeout); 192 } 193 194 for (i = 0; i < nfds; i++) { 195 fd->revents = 0; 196 fd++; 197 } 198 199 rc = ppoll(fds, nfds, timeout, sigmask); 200 if (rc == 0 && timeout) { 201 rc = -ETIMEDOUT; 202 } 203 else if (rc < 0) { 204 rc = -errno; 205 } 206 207 if (timeout) { 208 clock_gettime(CLOCK_MONOTONIC_RAW, &now); 209 subtract_timespecs(&future, &now, timeout); 210 } 211 212 return rc; 213 } 214 215 int wait_for_dev_input_access() 216 { 217 /* Wait for /dev/input/event* files to become accessible by 218 * having group 'input'. Setting these files to have 'rw' 219 * access to group 'input' is done through a udev rule 220 * installed by adhd into /lib/udev/rules.d. 221 * 222 * Wait for up to 2 seconds for the /dev/input/event* files to be 223 * readable by gavd. 224 * 225 * TODO(thutt): This could also be done with a udev enumerate 226 * and then a udev monitor. 227 */ 228 const unsigned max_iterations = 4; 229 unsigned i = 0; 230 231 while (i < max_iterations) { 232 int readable; 233 struct timeval timeout; 234 const char * const pathname = "/dev/input/event0"; 235 236 timeout.tv_sec = 0; 237 timeout.tv_usec = 500000; /* 1/2 second. */ 238 readable = access(pathname, R_OK); 239 240 /* If the file could be opened, then the udev rule has been 241 * applied and gavd can read the event files. If there are no 242 * event files, then we don't need to wait. 243 * 244 * If access does not become available, then headphone & 245 * microphone jack autoswitching will not function properly. 246 */ 247 if (readable == 0 || (readable == -1 && errno == ENOENT)) { 248 /* Access allowed, or file does not exist. */ 249 break; 250 } 251 if (readable != -1 || errno != EACCES) { 252 syslog(LOG_ERR, "Bad access for input devs."); 253 return errno; 254 } 255 select(1, NULL, NULL, NULL, &timeout); 256 ++i; 257 } 258 259 return 0; 260 } 261