forked from machinekit/machinekit-hal
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrtapi_task.c
More file actions
324 lines (249 loc) · 9.14 KB
/
rtapi_task.c
File metadata and controls
324 lines (249 loc) · 9.14 KB
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/********************************************************************
* Description: rtapi_task.c
* This file, 'rtapi_task.c', implements the task-
* related functions for realtime modules. See rtapi.h
* for more info.
*
* The functions here can be customized by defining
* 'hook' functions in a separate source file for the
* thread system, and define a macro indicating that the
* definition exists. The functions below that accept
* hooks are preceded by a prototype for the hook
* function.
*
* Copyright 2006-2013 Various Authors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
********************************************************************/
#include "config.h" // build configuration
#include "rtapi.h" // these functions
#include "rtapi_common.h" // RTAPI macros and decls
#include "rtapi_flavor.h" // flavor_*
/*
These functions are completely different between each userland
thread system, so these are defined in rtapi_module.c for kernel
threads systems and $THREADS.c for the userland thread systems
int rtapi_init(const char *modname)
int rtapi_exit(int id)
*/
/* priority functions */
int rtapi_prio_highest(void) {
return PRIO_HIGHEST;
}
int rtapi_prio_lowest(void) {
return PRIO_LOWEST;
}
int rtapi_prio_next_higher(int prio) {
/* next higher priority for arg */
prio++;
/* return a valid priority for out of range arg */
if (prio > rtapi_prio_highest())
return rtapi_prio_highest();
if (prio < rtapi_prio_lowest())
return rtapi_prio_lowest();
return prio;
}
int rtapi_prio_next_lower(int prio) {
/* next lower priority for arg */
prio--;
/* return a valid priority for out of range arg */
if (prio > rtapi_prio_highest())
return rtapi_prio_highest();
if (prio < rtapi_prio_lowest())
return rtapi_prio_lowest();
return prio;
}
#ifdef RTAPI /* below functions not available to user programs */
#define IS_TASK_ID_VALID(task_id) \
if (task_id <= 0 || task_id >= RTAPI_MAX_TASKS) \
{ \
return -EINVAL; \
}
/* task setup and teardown functions */
int rtapi_task_new(const rtapi_task_args_t *args) {
int task_id;
int __attribute__((__unused__)) retval = 0;
task_data *task;
/* get the mutex */
rtapi_mutex_get(&(rtapi_data->mutex));
/* find an empty entry in the task array */
task_id = 1; // tasks start at one!
// go through task_array until an empty task slot is found
while ((task_id < RTAPI_MAX_TASKS) &&
(task_array[task_id].magic == TASK_MAGIC))
task_id++;
// if task_array is full, release lock and return error
if (task_id == RTAPI_MAX_TASKS) {
rtapi_mutex_give(&(rtapi_data->mutex));
return -ENOMEM;
}
task = &(task_array[task_id]);
// if requested priority is invalid, release lock and return error
if (args->prio < rtapi_prio_lowest() ||
args->prio > rtapi_prio_highest()) {
rtapi_print_msg(RTAPI_MSG_ERR,
"New task %d '%s:%d': invalid priority %d "
"(highest=%d lowest=%d)\n",
task_id, args->name, rtapi_instance, args->prio,
rtapi_prio_highest(),
rtapi_prio_lowest());
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
/* Allow RT threads to use nowait. Required for external timing.
if ((args->flags & (TF_NOWAIT|TF_NONRT)) == TF_NOWAIT) {
rtapi_print_msg(RTAPI_MSG_ERR,"task '%s' : nowait flag invalid for RT thread\n",
args->name);
rtapi_mutex_give(&(rtapi_data->mutex));
return -EINVAL;
}
*/
// task slot found; reserve it and release lock
rtapi_print_msg(
RTAPI_MSG_DBG,
"Creating new task %d '%s:%d': "
"req prio %d (highest=%d lowest=%d) stack=%lu fp=%d flags=%d "
"cgname=%s\n",
task_id, args->name, rtapi_instance, args->prio,
rtapi_prio_highest(),
rtapi_prio_lowest(),
args->stacksize, args->uses_fp, args->flags, args->cgname);
task->magic = TASK_MAGIC;
/* fill out task structure */
task->owner = args->owner;
task->arg = args->arg;
task->stacksize = (args->stacksize < MIN_STACKSIZE) ? MIN_STACKSIZE : args->stacksize;
task->taskcode = args->taskcode;
task->prio = args->prio;
task->flags = args->flags;
task->uses_fp = args->uses_fp;
task->cpu = args->cpu_id > -1 ? args->cpu_id : rtapi_data->rt_cpu;
strncpy(task->cgname, args->cgname, RTAPI_LINELEN);
rtapi_print_msg(RTAPI_MSG_DBG, "Task CPU: %d\n", task->cpu);
rtapi_snprintf(task->name, sizeof(task->name),
"%s:%d", args->name, rtapi_instance);
task->name[sizeof(task->name) - 1] = '\0';
/* userland threads: flavor_task_new_hook() should perform any
thread system-specific tasks, and return task_id or an error code back to
the caller (how do we know the diff between an error and a
task_id???). */
task->state = USERLAND; // userland threads don't track this
retval = flavor_task_new_hook(NULL, task, task_id);
if (retval == -ENOSYS) // Unimplemented
retval = task_id;
rtapi_data->task_count++;
rtapi_mutex_give(&(rtapi_data->mutex));
/* announce the birth of a brand new baby task */
rtapi_print_msg(RTAPI_MSG_DBG,
"RTAPI: task %02d installed by module %02d, priority %d, code: %p\n",
task_id, task->owner, task->prio, args->taskcode);
return task_id;
}
int rtapi_task_delete(int task_id) {
task_data *task;
int retval = 0;
IS_TASK_ID_VALID(task_id)
task = &(task_array[task_id]);
/* validate task handle */
if (task->magic != TASK_MAGIC) // nothing to delete
return -EINVAL;
if (task->state != DELETE_LOCKED) // we don't already hold mutex
rtapi_mutex_get(&(rtapi_data->mutex));
flavor_task_delete_hook(NULL, task,task_id);
if (task->state != DELETE_LOCKED) // we don't already hold mutex
rtapi_mutex_give(&(rtapi_data->mutex));
task->state = EMPTY;
task->magic = 0;
rtapi_print_msg(RTAPI_MSG_DBG, "rt_task_delete %d \"%s\"\n", task_id,
task->name );
return retval;
}
/* all threads systems must define this hook */
int rtapi_task_start(int task_id, unsigned long int period_nsec) {
task_data *task;
IS_TASK_ID_VALID(task_id)
task = &task_array[task_id];
/* validate task handle */
if (task->magic != TASK_MAGIC)
return -EINVAL;
if (period_nsec < period) period_nsec = period;
task->period = period_nsec;
task->ratio = period_nsec / period;
// limit PLL correction values to +/-1% of cycle time
task->pll_correction_limit = period_nsec / 100;
task->pll_correction = 0;
rtapi_print_msg(RTAPI_MSG_DBG,
"rtapi_task_start: starting task %d '%s'\n",
task_id, task->name);
rtapi_print_msg(RTAPI_MSG_DBG, "RTAPI: period_nsec: %ld\n", period_nsec);
return flavor_task_start_hook(NULL, task,task_id);
}
int rtapi_task_stop(int task_id) {
task_data *task;
IS_TASK_ID_VALID(task_id)
task = &task_array[task_id];
/* validate task handle */
if (task->magic != TASK_MAGIC)
return -EINVAL;
flavor_task_stop_hook(NULL, task,task_id);
return 0;
}
int rtapi_task_pause(int task_id) {
task_data *task;
IS_TASK_ID_VALID(task_id)
task = &task_array[task_id];
/* validate task handle */
if (task->magic != TASK_MAGIC)
return -EINVAL;
return flavor_task_pause_hook(NULL, task, task_id);
}
int rtapi_wait(const int flag) {
return flavor_task_wait_hook(NULL, flag);
}
int rtapi_task_resume(int task_id) {
task_data *task;
IS_TASK_ID_VALID(task_id)
task = &task_array[task_id];
/* validate task handle */
if (task->magic != TASK_MAGIC)
return -EINVAL;
return flavor_task_resume_hook(NULL, task, task_id);
}
int rtapi_task_self(void) {
return flavor_task_self_hook(NULL);
}
long long rtapi_task_pll_get_reference(void) {
return flavor_task_pll_get_reference_hook(NULL);
}
int rtapi_task_pll_set_correction(long value) {
return flavor_task_pll_set_correction_hook(NULL, value);
}
#endif /* RTAPI */
#ifdef RTAPI
EXPORT_SYMBOL(rtapi_prio_highest);
EXPORT_SYMBOL(rtapi_prio_lowest);
EXPORT_SYMBOL(rtapi_prio_next_higher);
EXPORT_SYMBOL(rtapi_prio_next_lower);
EXPORT_SYMBOL(rtapi_task_new);
EXPORT_SYMBOL(rtapi_task_delete);
EXPORT_SYMBOL(rtapi_task_start);
EXPORT_SYMBOL(rtapi_task_stop);
EXPORT_SYMBOL(rtapi_task_pause);
EXPORT_SYMBOL(rtapi_wait);
EXPORT_SYMBOL(rtapi_task_resume);
EXPORT_SYMBOL(rtapi_task_self);
EXPORT_SYMBOL(rtapi_task_pll_get_reference);
EXPORT_SYMBOL(rtapi_task_pll_set_correction);
#endif