/* * Copyright (C) 2014 Philippe Gerum . * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include #include #include #include "cobalt/internal.h" #include "internal.h" /** * @ingroup trank * @{ */ /** * Make a thread periodic (compatibility service). * * This service makes the POSIX @a thread periodic. * * @param thread thread to arm a periodic timer for. * * @param starttp start time, expressed as an absolute value of the * CLOCK_REALTIME clock. * * @param periodtp period, expressed as a time interval. * * @return 0 on success; * @return an error number if: * - ESRCH, @a thread is invalid. * - ETIMEDOUT, the start time has already passed. * - EPERM, the caller is not a Xenomai thread. * - EINVAL, @a thread does not refer to the current thread. * * @note Unlike the original Xenomai 2.x call, this emulation does not * delay the caller waiting for the first periodic release point. In * addition, @a thread must be equal to pthread_self(). * * @deprecated This service is a non-portable extension of the Xenomai * 2.x POSIX interface, not available with Xenomai 3.x. Instead, * Cobalt-based applications should set up a periodic timer using the * timer_create(), timer_settime() call pair, then wait for release * points via sigwaitinfo(). Overruns can be detected by looking at * the siginfo.si_overrun field. Alternatively, applications may * obtain a file descriptor referring to a Cobalt timer via the * timerfd() call, and read() from it to wait for timeouts. */ int pthread_make_periodic_np(pthread_t thread, struct timespec *starttp, struct timespec *periodtp) { struct trank_context *tc; struct itimerspec its; struct sigevent sev; int ret; tc = trank_get_context(); if (tc == NULL) return EPERM; if (thread != pthread_self()) return EINVAL; if (tc->periodic_timer == NULL) { memset(&sev, 0, sizeof(sev)); sev.sigev_signo = SIGPERIOD; sev.sigev_notify = SIGEV_SIGNAL|SIGEV_THREAD_ID; sev.sigev_notify_thread_id = cobalt_thread_pid(thread); ret = __RT(timer_create(CLOCK_REALTIME, &sev, &tc->periodic_timer)); if (ret) return -errno; } its.it_value = *starttp; its.it_interval = *periodtp; ret = __RT(timer_settime(tc->periodic_timer, TIMER_ABSTIME, &its, NULL)); if (ret) return -errno; return 0; } /** * Wait for the next periodic release point (compatibility service) * * Delay the current thread until the next periodic release point is * reached. The periodic timer should have been previously started for * @a thread by a call to pthread_make_periodic_np(). * * @param overruns_r If non-NULL, @a overruns_r shall be a pointer to * a memory location which will be written with the count of pending * overruns. This value is written to only when pthread_wait_np() * returns ETIMEDOUT or success. The memory location remains * unmodified otherwise. If NULL, this count will not be returned. * * @return Zero is returned upon success. If @a overruns_r is * non-NULL, zero is written to the pointed memory * location. Otherwise: * * - EWOULDBLOCK is returned if pthread_make_periodic_np() was not * called for the current thread. * * - EINTR is returned if @a thread was interrupted by a signal before * the next periodic release point was reached. * * - ETIMEDOUT is returned if a timer overrun occurred, which * indicates that a previous release point was missed by the calling * thread. If @a overruns_r is non-NULL, the count of pending overruns * is written to the pointed memory location. * * - EPERM is returned if this service was called from an invalid * context. * * @note If the current release point has already been reached at the * time of the call, the current thread immediately returns from this * service with no delay. * * @deprecated This service is a non-portable extension of the Xenomai * 2.x POSIX interface, not available with Xenomai 3.x. Instead, * Cobalt-based applications should set up a periodic timer using the * timer_create(), timer_settime() call pair, then wait for release * points via sigwaitinfo(). Overruns can be detected by looking at * the siginfo.si_overrun field. Alternatively, applications may * obtain a file descriptor referring to a Cobalt timer via the * timerfd() call, and read() from it to wait for timeouts. */ int pthread_wait_np(unsigned long *overruns_r) { struct trank_context *tc; siginfo_t si; int sig; tc = trank_get_context(); if (tc == NULL) return EPERM; if (tc->periodic_timer == NULL) return EWOULDBLOCK; for (;;) { sig = __RT(sigwaitinfo(&trank_sigperiod_set, &si)); if (sig == SIGPERIOD) break; if (errno == EINTR) return EINTR; panic("cannot wait for next period, %s", symerror(-errno)); } if (overruns_r) *overruns_r = si.si_overrun; return 0; } /** @} */