hc
2024-11-01 2f529f9b558ca1c1bd74be7437a84e4711743404
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
 * Copyright (C) 2014 Philippe Gerum <rpm@xenomai.org>.
 *
 * 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 <xeno_config.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <memory.h>
#include <boilerplate/ancillaries.h>
#include <boilerplate/signal.h>
#include <trank/posix/pthread.h>
#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;
}
 
/** @} */