summaryrefslogtreecommitdiffstats
path: root/c_user/user_extensions.rst
blob: 664d70ad4cf23dbe506d36bef324d4a97c902824 (plain) (blame)
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
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
.. comment SPDX-License-Identifier: CC-BY-SA-4.0

.. COMMENT: COPYRIGHT (c) 1988-2008.
.. COMMENT: On-Line Applications Research Corporation (OAR).
.. COMMENT: All rights reserved.

.. _User Extensions Manager:

User Extensions Manager
#######################

.. index:: user extensions

Introduction
============

The RTEMS User Extensions Manager allows the application developer to augment
the executive by allowing them to supply extension routines which are invoked
at critical system events.  The directives provided by the user extensions
manager are:

- rtems_extension_create_ - Create an extension set

- rtems_extension_ident_ - Get ID of an extension set

- rtems_extension_delete_ - Delete an extension set

Background
==========

User extension routines are invoked when the following system events occur:

- Task creation

- Task initiation

- Task reinitiation

- Task deletion

- Task context switch

- Post task context switch

- Task begin

- Task exits

- Fatal error detection

These extensions are invoked as a function with arguments that are appropriate
to the system event.

Extension Sets
--------------
.. index:: extension set

An extension set is defined as a set of routines which are invoked at each of
the critical system events at which user extension routines are invoked.
Together a set of these routines typically perform a specific functionality
such as performance monitoring or debugger support.  RTEMS is informed of the
entry points which constitute an extension set via the following
structure:.. index:: rtems_extensions_table

.. code-block:: c

    typedef struct {
        rtems_task_create_extension      thread_create;
        rtems_task_start_extension       thread_start;
        rtems_task_restart_extension     thread_restart;
        rtems_task_delete_extension      thread_delete;
        rtems_task_switch_extension      thread_switch;
        rtems_task_begin_extension       thread_begin;
        rtems_task_exitted_extension     thread_exitted;
        rtems_fatal_extension            fatal;
    } rtems_extensions_table;

RTEMS allows the user to have multiple extension sets active at the same time.
First, a single static extension set may be defined as the application's User
Extension Table which is included as part of the Configuration Table.  This
extension set is active for the entire life of the system and may not be
deleted.  This extension set is especially important because it is the only way
the application can provided a FATAL error extension which is invoked if RTEMS
fails during the initialize_executive directive.  The static extension set is
optional and may be configured as NULL if no static extension set is required.

Second, the user can install dynamic extensions using the
``rtems_extension_create`` directive.  These extensions are RTEMS objects in
that they have a name, an ID, and can be dynamically created and deleted.  In
contrast to the static extension set, these extensions can only be created and
installed after the initialize_executive directive successfully completes
execution.  Dynamic extensions are useful for encapsulating the functionality
of an extension set.  For example, the application could use extensions to
manage a special coprocessor, do performance monitoring, and to do stack bounds
checking.  Each of these extension sets could be written and installed
independently of the others.

All user extensions are optional and RTEMS places no naming restrictions on the
user. The user extension entry points are copied into an internal RTEMS
structure. This means the user does not need to keep the table after creating
it, and changing the handler entry points dynamically in a table once created
has no effect. Creating a table local to a function can save space in space
limited applications.

Extension switches do not effect the context switch overhead if no switch
handler is installed.

TCB Extension Area
------------------
.. index:: TCB extension area

RTEMS provides for a pointer to a user-defined data area for each extension set
to be linked to each task's control block.  This set of pointers is an
extension of the TCB and can be used to store additional data required by the
user's extension functions.

The TCB extension is an array of pointers in the TCB. The index into the table
can be obtained from the extension id returned when the extension is
created:

.. index:: rtems extensions table index

.. code-block:: c

    index = rtems_object_id_get_index(extension_id);

The number of pointers in the area is the same as the number of user extension
sets configured.  This allows an application to augment the TCB with
user-defined information.  For example, an application could implement task
profiling by storing timing statistics in the TCB's extended memory area.  When
a task context switch is being executed, the ``TASK_SWITCH`` extension could
read a real-time clock to calculate how long the task being swapped out has run
as well as timestamp the starting time for the task being swapped in.

If used, the extended memory area for the TCB should be allocated and the TCB
extension pointer should be set at the time the task is created or started by
either the ``TASK_CREATE`` or ``TASK_START`` extension.  The application is
responsible for managing this extended memory area for the TCBs.  The memory
may be reinitialized by the ``TASK_RESTART`` extension and should be
deallocated by the ``TASK_DELETE`` extension when the task is deleted.  Since
the TCB extension buffers would most likely be of a fixed size, the RTEMS
partition manager could be used to manage the application's extended memory
area.  The application could create a partition of fixed size TCB extension
buffers and use the partition manager's allocation and deallocation directives
to obtain and release the extension buffers.

Extensions
----------

The sections that follow will contain a description of each extension.  Each
section will contain a prototype of a function with the appropriate calling
sequence for the corresponding extension.  The names given for the C function
and its arguments are all defined by the user.  The names used in the examples
were arbitrarily chosen and impose no naming conventions on the user.

TASK_CREATE Extension
~~~~~~~~~~~~~~~~~~~~~

The TASK_CREATE extension directly corresponds to the ``rtems_task_create``
directive.  If this extension is defined in any static or dynamic extension set
and a task is being created, then the extension routine will automatically be
invoked by RTEMS.  The extension should have a prototype similar to the
following:

.. index:: rtems_task_create_extension
.. index:: rtems_extension

.. code-block:: c

    bool user_task_create(
       rtems_tcb *current_task,
       rtems_tcb *new_task
    );

where ``current_task`` can be used to access the TCB for the currently
executing task, and new_task can be used to access the TCB for the new task
being created.  This extension is invoked from the ``rtems_task_create``
directive after ``new_task`` has been completely initialized, but before it is
placed on a ready TCB chain.

The user extension is expected to return the boolean value ``true`` if it
successfully executed and ``false`` otherwise.  A task create user extension
will frequently attempt to allocate resources.  If this allocation fails, then
the extension should return ``false`` and the entire task create operation will
fail.

TASK_START Extension
~~~~~~~~~~~~~~~~~~~~

The ``TASK_START`` extension directly corresponds to the task_start directive.
If this extension is defined in any static or dynamic extension set and a task
is being started, then the extension routine will automatically be invoked by
RTEMS.  The extension should have a prototype similar to the following:

.. index:: rtems_task_start_extension

.. code-block:: c

    void user_task_start(
        rtems_tcb *current_task,
        rtems_tcb *started_task
    );

where current_task can be used to access the TCB for the currently executing
task, and started_task can be used to access the TCB for the dormant task being
started. This extension is invoked from the task_start directive after
started_task has been made ready to start execution, but before it is placed on
a ready TCB chain.

TASK_RESTART Extension
~~~~~~~~~~~~~~~~~~~~~~

The ``TASK_RESTART`` extension directly corresponds to the task_restart
directive.  If this extension is defined in any static or dynamic extension set
and a task is being restarted, then the extension should have a prototype
similar to the following:

.. index:: rtems_task_restart_extension

.. code-block:: c

    void user_task_restart(
        rtems_tcb *current_task,
        rtems_tcb *restarted_task
    );

where current_task can be used to access the TCB for the currently executing
task, and restarted_task can be used to access the TCB for the task being
restarted. This extension is invoked from the task_restart directive after
restarted_task has been made ready to start execution, but before it is placed
on a ready TCB chain.

TASK_DELETE Extension
~~~~~~~~~~~~~~~~~~~~~

The ``TASK_DELETE`` extension is associated with the task_delete directive.  If
this extension is defined in any static or dynamic extension set and a task is
being deleted, then the extension routine will automatically be invoked by
RTEMS.  The extension should have a prototype similar to the
following:

.. index:: rtems_task_delete_extension

.. code-block:: c

    void user_task_delete(
        rtems_tcb *current_task,
        rtems_tcb *deleted_task
    );

where current_task can be used to access the TCB for the currently executing
task, and deleted_task can be used to access the TCB for the task being
deleted. This extension is invoked from the task_delete directive after the TCB
has been removed from a ready TCB chain, but before all its resources including
the TCB have been returned to their respective free pools.  This extension
should not call any RTEMS directives if a task is deleting itself (current_task
is equal to deleted_task).

TASK_SWITCH Extension
~~~~~~~~~~~~~~~~~~~~~

The ``TASK_SWITCH`` extension corresponds to a task context switch.  If this
extension is defined in any static or dynamic extension set and a task context
switch is in progress, then the extension routine will automatically be invoked
by RTEMS.  The extension should have a prototype similar to the following:

.. index:: rtems_task_switch_extension

.. code-block:: c

    void user_task_switch(
        rtems_tcb *current_task,
        rtems_tcb *heir_task
    );

where current_task can be used to access the TCB for the task that is being
swapped out, and heir_task can be used to access the TCB for the task being
swapped in.  This extension is invoked from RTEMS' dispatcher routine after the
current_task context has been saved, but before the heir_task context has been
restored.  This extension should not call any RTEMS directives.

TASK_BEGIN Extension
~~~~~~~~~~~~~~~~~~~~

The ``TASK_BEGIN`` extension is invoked when a task begins execution.  It is
invoked immediately before the body of the starting procedure and executes in
the context in the task.  This user extension have a prototype similar to the
following:

.. index:: rtems_task_begin_extension

.. code-block:: c

    void user_task_begin(
        rtems_tcb *current_task
    );

where current_task can be used to access the TCB for the currently executing
task which has begun.  The distinction between the ``TASK_BEGIN`` and
TASK_START extension is that the ``TASK_BEGIN`` extension is executed in the
context of the actual task while the TASK_START extension is executed in the
context of the task performing the task_start directive.  For most extensions,
this is not a critical distinction.

TASK_EXITTED Extension
~~~~~~~~~~~~~~~~~~~~~~

The ``TASK_EXITTED`` extension is invoked when a task exits the body of the
starting procedure by either an implicit or explicit return statement.  This
user extension have a prototype similar to the following:

.. index:: rtems_task_exitted_extension

.. code-block:: c

    void user_task_exitted(
        rtems_tcb *current_task
    );

where current_task can be used to access the TCB for the currently executing
task which has just exitted.

Although exiting of task is often considered to be a fatal error, this
extension allows recovery by either restarting or deleting the exiting task.
If the user does not wish to recover, then a fatal error may be reported.  If
the user does not provide a ``TASK_EXITTED`` extension or the provided handler
returns control to RTEMS, then the RTEMS default handler will be used.  This
default handler invokes the directive fatal_error_occurred with the
``RTEMS_TASK_EXITTED`` directive status.

FATAL Error Extension
~~~~~~~~~~~~~~~~~~~~~

The ``FATAL`` error extension is associated with the fatal_error_occurred
directive.  If this extension is defined in any static or dynamic extension set
and the fatal_error_occurred directive has been invoked, then this extension
will be called.  This extension should have a prototype similar to the
following:

.. index:: rtems_fatal_extension

.. code-block:: c

    void user_fatal_error(
        Internal_errors_Source  the_source,
        bool                    is_internal,
        uint32_t                the_error
    );

where the_error is the error code passed to the fatal_error_occurred
directive. This extension is invoked from the fatal_error_occurred directive.

If defined, the user's ``FATAL`` error extension is invoked before RTEMS'
default fatal error routine is invoked and the processor is stopped.  For
example, this extension could be used to pass control to a debugger when a
fatal error occurs.  This extension should not call any RTEMS directives.

Order of Invocation
-------------------

When one of the critical system events occur, the user extensions are invoked
in either "forward" or "reverse" order.  Forward order indicates that the
static extension set is invoked followed by the dynamic extension sets in the
order in which they were created.  Reverse order means that the dynamic
extension sets are invoked in the opposite of the order in which they were
created followed by the static extension set.  By invoking the extension sets
in this order, extensions can be built upon one another.  At the following
system events, the extensions are invoked in forward order:

#. Task creation

#. Task initiation

#. Task reinitiation

#. Task deletion

#. Task context switch

#. Post task context switch

#. Task begins to execute

At the following system events, the extensions are invoked in reverse order:

#. Task deletion

#. Fatal error detection

At these system events, the extensions are invoked in reverse order to insure
that if an extension set is built upon another, the more complicated extension
is invoked before the extension set it is built upon.  For example, by invoking
the static extension set last it is known that the "system" fatal error
extension will be the last fatal error extension executed.  Another example is
use of the task delete extension by the Standard C Library.  Extension sets
which are installed after the Standard C Library will operate correctly even if
they utilize the C Library because the C Library's ``TASK_DELETE`` extension is
invoked after that of the other extensions.

Operations
==========

Creating an Extension Set
-------------------------

The ``rtems_extension_create`` directive creates and installs an extension set
by allocating a Extension Set Control Block (ESCB), assigning the extension set
a user-specified name, and assigning it an extension set ID.  Newly created
extension sets are immediately installed and are invoked upon the next system
even supporting an extension.

Obtaining Extension Set IDs
---------------------------

When an extension set is created, RTEMS generates a unique extension set ID and
assigns it to the created extension set until it is deleted.  The extension ID
may be obtained by either of two methods.  First, as the result of an
invocation of the ``rtems_extension_create`` directive, the extension set ID is
stored in a user provided location.  Second, the extension set ID may be
obtained later using the ``rtems_extension_ident`` directive.  The extension
set ID is used by other directives to manipulate this extension set.

Deleting an Extension Set
-------------------------

The ``rtems_extension_delete`` directive is used to delete an extension set.
The extension set's control block is returned to the ESCB free list when it is
deleted.  An extension set can be deleted by a task other than the task which
created the extension set.  Any subsequent references to the extension's name
and ID are invalid.

Directives
==========

This section details the user extension manager's directives.  A subsection is
dedicated to each of this manager's directives and describes the calling
sequence, related constants, usage, and status codes.

.. _rtems_extension_create:

EXTENSION_CREATE - Create a extension set
-----------------------------------------
.. index:: create an extension set

**CALLING SEQUENCE:**

.. index:: rtems_extension_create

.. code-block:: c

    rtems_status_code rtems_extension_create(
        rtems_name              name,
        rtems_extensions_table *table,
        rtems_id               *id
    );

**DIRECTIVE STATUS CODES:**

.. list-table::
 :class: rtems-table

 * - ``RTEMS_SUCCESSFUL``
   - extension set created successfully
 * - ``RTEMS_INVALID_NAME``
   - invalid extension set name
 * - ``RTEMS_TOO_MANY``
   - too many extension sets created

**DESCRIPTION:**

This directive creates a extension set.  The assigned extension set id is
returned in id.  This id is used to access the extension set with other user
extension manager directives.  For control and maintenance of the extension
set, RTEMS allocates an ESCB from the local ESCB free pool and initializes it.

**NOTES:**

This directive will not cause the calling task to be
preempted.

.. _rtems_extension_ident:

EXTENSION_IDENT - Get ID of a extension set
-------------------------------------------
.. index:: get ID of an extension set
.. index:: obtain ID of an extension set

**CALLING SEQUENCE:**

.. index:: rtems_extension_ident

.. code-block:: c

    rtems_status_code rtems_extension_ident(
        rtems_name  name,
        rtems_id   *id
    );

**DIRECTIVE STATUS CODES:**

.. list-table::
 :class: rtems-table

 * - ``RTEMS_SUCCESSFUL``
   - extension set identified successfully
 * - ``RTEMS_INVALID_NAME``
   - extension set name not found

**DESCRIPTION:**

This directive obtains the extension set id associated with the extension set
name to be acquired.  If the extension set name is not unique, then the
extension set id will match one of the extension sets with that name.  However,
this extension set id is not guaranteed to correspond to the desired extension
set.  The extension set id is used to access this extension set in other
extension set related directives.

**NOTES:**

This directive will not cause the running task to be preempted.

.. _rtems_extension_delete:

EXTENSION_DELETE - Delete a extension set
-----------------------------------------
.. index:: delete an extension set

**CALLING SEQUENCE:**

.. index:: rtems_extension_delete

.. code-block:: c

    rtems_status_code rtems_extension_delete(
        rtems_id id
    );

**DIRECTIVE STATUS CODES:**

.. list-table::
 :class: rtems-table

 * - ``RTEMS_SUCCESSFUL``
   - extension set deleted successfully
 * - ``RTEMS_INVALID_ID``
   - invalid extension set id

**DESCRIPTION:**

This directive deletes the extension set specified by ``id``.  If the extension
set is running, it is automatically canceled.  The ESCB for the deleted
extension set is reclaimed by RTEMS.

**NOTES:**

This directive will not cause the running task to be preempted.

A extension set can be deleted by a task other than the task which created the
extension set.

**NOTES:**

This directive will not cause the running task to be preempted.