@@ -427,5 +427,207 @@ static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
return ret;
}
+/* select(2) */
+static inline abi_long do_freebsd_select(CPUArchState *env, int n,
+ abi_ulong rfd_addr, abi_ulong wfd_addr, abi_ulong efd_addr,
+ abi_ulong target_tv_addr)
+{
+ fd_set rfds, wfds, efds;
+ fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+ struct timeval tv, *tvp;
+ abi_long ret, error;
+
+ ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (target_tv_addr != 0) {
+ if (t2h_freebsd_timeval(&tv, target_tv_addr)) {
+ return -TARGET_EFAULT;
+ }
+ tvp = &tv;
+ } else {
+ tvp = NULL;
+ }
+
+ ret = get_errno(safe_select(n, rfds_ptr, wfds_ptr, efds_ptr, tvp));
+
+ if (!is_error(ret)) {
+ if (rfd_addr != 0) {
+ error = copy_to_user_fdset(rfd_addr, &rfds, n);
+ if (error != 0) {
+ return error;
+ }
+ }
+ if (wfd_addr != 0) {
+ error = copy_to_user_fdset(wfd_addr, &wfds, n);
+ if (error != 0) {
+ return error;
+ }
+ }
+ if (efd_addr != 0) {
+ error = copy_to_user_fdset(efd_addr, &efds, n);
+ if (error != 0) {
+ return error;
+ }
+ }
+ if (target_tv_addr != 0) {
+ error = h2t_freebsd_timeval(&tv, target_tv_addr);
+ if (is_error(error)) {
+ return error;
+ }
+ }
+ }
+ return ret;
+}
+
+/* pselect(2) */
+static inline abi_long do_freebsd_pselect(CPUArchState *env, int n,
+ abi_ulong rfd_addr, abi_ulong wfd_addr, abi_ulong efd_addr,
+ abi_ulong ts_addr, abi_ulong set_addr)
+{
+ CPUState *cpu = env_cpu(env);
+ TaskState *tstate = cpu->opaque;
+ fd_set rfds, wfds, efds;
+ fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+ sigset_t *set_ptr;
+ struct timespec ts, *ts_ptr;
+ void *p;
+ abi_long ret, error;
+
+ ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+ if (is_error(ret)) {
+ return ret;
+ }
+ ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+ if (is_error(ret)) {
+ return ret;
+ }
+ ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+ if (is_error(ret)) {
+ return ret;
+ }
+
+ /* Unlike select(), pselect() uses struct timespec instead of timeval */
+ if (ts_addr) {
+ if (t2h_freebsd_timespec(&ts, ts_addr)) {
+ return -TARGET_EFAULT;
+ }
+ ts_ptr = &ts;
+ } else {
+ ts_ptr = NULL;
+ }
+
+ if (set_addr != 0) {
+ p = lock_user(VERIFY_READ, set_addr, sizeof(target_sigset_t), 1);
+ if (p == NULL) {
+ return -TARGET_EFAULT;
+ }
+ target_to_host_sigset(&tstate->sigsuspend_mask, p);
+ unlock_user(p, set_addr, 0);
+ set_ptr = &tstate->sigsuspend_mask;
+ } else {
+ set_ptr = NULL;
+ }
+
+ ret = get_errno(safe_pselect(n, rfds_ptr, wfds_ptr, efds_ptr, ts_ptr,
+ set_ptr));
+ if (ret != -TARGET_ERESTART) {
+ tstate->in_sigsuspend = true;
+ }
+ if (!is_error(ret)) {
+ if (rfd_addr != 0) {
+ error = copy_to_user_fdset(rfd_addr, &rfds, n);
+ if (is_error(error)) {
+ return error;
+ }
+ }
+ if (wfd_addr != 0) {
+ error = copy_to_user_fdset(wfd_addr, &wfds, n);
+ if (is_error(error)) {
+ return error;
+ }
+ }
+ if (efd_addr != 0) {
+ error = copy_to_user_fdset(efd_addr, &efds, n);
+ if (is_error(error)) {
+ return error;
+ }
+ }
+ }
+ return ret;
+}
+
+/* ppoll(2) */
+static inline abi_long do_freebsd_ppoll(CPUArchState *env, abi_long arg1,
+ abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+ CPUState *cpu = env_cpu(env);
+ TaskState *tstate = cpu->opaque;
+ abi_long ret;
+ nfds_t i, nfds = arg2;
+ struct pollfd *pfd;
+ struct target_pollfd *target_pfd;
+ struct timespec ts, *ts_ptr;
+ sigset_t *set_ptr;
+ void *p;
+
+ target_pfd = lock_user(VERIFY_WRITE, arg1,
+ sizeof(struct target_pollfd) * nfds, 1);
+ if (!target_pfd) {
+ return -TARGET_EFAULT;
+ }
+ pfd = alloca(sizeof(struct pollfd) * nfds);
+ for (i = 0; i < nfds; i++) {
+ pfd[i].fd = tswap32(target_pfd[i].fd);
+ pfd[i].events = tswap16(target_pfd[i].events);
+ }
+
+ /* Unlike poll(), ppoll() uses struct timespec. */
+ if (arg3) {
+ if (t2h_freebsd_timespec(&ts, arg3)) {
+ return -TARGET_EFAULT;
+ }
+ ts_ptr = &ts;
+ } else {
+ ts_ptr = NULL;
+ }
+
+ if (arg4 != 0) {
+ p = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
+ if (p == NULL) {
+ return -TARGET_EFAULT;
+ }
+ target_to_host_sigset(&tstate->sigsuspend_mask, p);
+ unlock_user(p, arg4, 0);
+ set_ptr = &tstate->sigsuspend_mask;
+ } else {
+ set_ptr = NULL;
+ }
+
+ ret = get_errno(ppoll(pfd, nfds, ts_ptr, set_ptr));
+ if (ret != -TARGET_ERESTART) {
+ tstate->in_sigsuspend = true;
+ }
+ if (!is_error(ret)) {
+ for (i = 0; i < nfds; i++) {
+ target_pfd[i].revents = tswap16(pfd[i].revents);
+ }
+ }
+ unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
+
+ return ret;
+}
+
+/* kqueue(2) */
#endif /* FREEBSD_OS_TIME_H */