source: rtems/c/src/lib/libc/newlibc.c @ 4bab8e2d

4.104.114.84.95
Last change on this file since 4bab8e2d was 4bab8e2d, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 6, 1996 at 5:45:12 PM

get_errno: no longer needed by gnat runtime

  • Property mode set to 100644
File size: 8.9 KB
Line 
1#if defined(RTEMS_NEWLIB)
2
3/*
4 *  COPYRIGHT (c) 1994 by Division Incorporated
5 *
6 *  To anyone who acknowledges that this file is provided "AS IS"
7 *  without any express or implied warranty:
8 *      permission to use, copy, modify, and distribute this file
9 *      for any purpose is hereby granted without fee, provided that
10 *      the above copyright notice and this notice appears in all
11 *      copies, and that the name of Division Incorporated not be
12 *      used in advertising or publicity pertaining to distribution
13 *      of the software without specific, written prior permission.
14 *      Division Incorporated makes no representations about the
15 *      suitability of this software for any purpose.
16 *
17 *  Description:
18 *      Implementation of hooks for the CYGNUS newlib libc
19 *      These hooks set things up so that:
20 *              '_REENT' is switched at task switch time.
21 *
22 *
23 *  TODO:
24 *
25 *  NOTE:
26 *
27 *  $Id$
28 *
29 */
30
31#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
32#include <rtems.h>
33#include <libcsupport.h>
34#include <stdlib.h>             /* for free() */
35#include <string.h>             /* for memset() */
36
37#include <sys/reent.h>          /* for extern of _REENT (aka _impure_ptr) */
38#include <errno.h>
39
40/*
41 *  NOTE: When using RTEMS fake stat, fstat, and isatty, all output
42 *        is line buffered so this setvbuf is not necessary.  This
43 *        setvbuf insures that we can redirect the output of a test
44 *        on the UNIX simulator and it is in the same order as for a
45 *        real target.
46 *  NOTE:
47 *        There is some problem with doing this on the hpux version
48 *        of the UNIX simulator (symptom is printf core dumps), so
49 *        we just don't for now.
50 *        Not sure if this is a problem with hpux, newlib, or something else.
51 */
52 
53#if defined(RTEMS_UNIX) && !defined(hpux)
54#define NEED_SETVBUF
55#endif
56 
57#ifdef NEED_SETVBUF
58#include <stdio.h>
59#endif
60
61#include "internal.h"
62
63#define LIBC_NOTEPAD RTEMS_NOTEPAD_LAST
64
65
66int              libc_reentrant;        /* do we think we are reentrant? */
67struct _reent    libc_global_reent = _REENT_INIT(libc_global_reent);;
68
69/*
70 * CYGNUS newlib routine that does atexit() processing and flushes
71 *      stdio streams
72 *      undocumented
73 */
74
75extern void _wrapup_reent(struct _reent *);
76extern void _reclaim_reent(struct _reent *);
77
78void
79libc_wrapup(void)
80{
81    _wrapup_reent(0);
82    if (_REENT != &libc_global_reent)
83    {
84        _wrapup_reent(&libc_global_reent);
85#if 0
86        /* don't reclaim this one, just in case we do printfs */
87        /* on our way out to ROM */
88        _reclaim_reent(&libc_global_reent);
89#endif
90        _REENT = &libc_global_reent;
91    }
92}
93
94
95rtems_boolean
96libc_create_hook(rtems_tcb *current_task,
97                 rtems_tcb *creating_task)
98{
99    MY_task_set_note(creating_task, LIBC_NOTEPAD, 0);
100    return TRUE;
101}
102
103/*
104 * Called for all user TASKS (system tasks are MPCI Receive Server and IDLE)
105 */
106
107rtems_extension
108libc_start_hook(rtems_tcb *current_task,
109                rtems_tcb *starting_task)
110{
111    struct _reent *ptr;
112
113    /* NOTE: our malloc is reentrant without a reent ptr since
114     *  it is based on region manager
115     */
116
117    ptr = (struct _reent *) malloc(sizeof(struct _reent));
118
119    /* GCC extension: structure constants */
120    *ptr = (struct _reent) _REENT_INIT((*ptr));
121
122    MY_task_set_note(starting_task, LIBC_NOTEPAD, (rtems_unsigned32) ptr);
123}
124
125/*
126 * Called for all user TASKS (system tasks are MPCI Receive Server and IDLE)
127 *
128 *  NOTE: When using RTEMS fake stat, fstat, and isatty, all output
129 *        is line buffered so this setvbuf is not necessary.  This
130 *        setvbuf insures that we can redirect the output of a test
131 *        on the UNIX simulator and it is in the same order as for a
132 *        real target.
133 */
134 
135#ifdef NEED_SETVBUF
136rtems_extension
137libc_begin_hook(rtems_tcb *current_task)
138{
139  setvbuf( stdout, NULL, _IOLBF, BUFSIZ );
140}
141#endif
142
143rtems_extension
144libc_switch_hook(rtems_tcb *current_task,
145                 rtems_tcb *heir_task)
146{
147    rtems_unsigned32 impure_value;
148
149    /* XXX We can't use rtems_task_set_note() here since SYSI task has a
150     * tid of 0, which is treated specially (optimized, actually)
151     * by rtems_task_set_note
152     *
153     * NOTE:  The above comment is no longer true and we need to use
154     *        the extension data areas added about the same time.
155     */
156
157    /*
158     *  Don't touch the outgoing task if it has been deleted.
159     */
160
161    if ( !_States_Is_transient( current_task->current_state ) ) {
162      impure_value = (rtems_unsigned32) _REENT;
163      MY_task_set_note(current_task, LIBC_NOTEPAD, impure_value);
164    }
165
166    _REENT = (struct _reent *) MY_task_get_note(heir_task, LIBC_NOTEPAD);
167
168}
169
170/*
171 *  Function:   libc_delete_hook
172 *  Created:    94/12/10
173 *
174 *  Description:
175 *      Called when a task is deleted.
176 *      Must restore the new lib reentrancy state for the new current
177 *      task.
178 *
179 *  Parameters:
180 *
181 *
182 *  Returns:
183 *
184 *
185 *  Side Effects:
186 *
187 *  Notes:
188 *
189 *
190 *  Deficiencies/ToDo:
191 *
192 *
193 */
194rtems_extension
195libc_delete_hook(rtems_tcb *current_task,
196                 rtems_tcb *deleted_task)
197{
198    struct _reent *ptr;
199
200    /*
201     * The reentrancy structure was allocated by newlib using malloc()
202     */
203
204    if (current_task == deleted_task)
205    {
206      ptr = _REENT;
207    }
208    else
209    {
210      ptr = (struct _reent *) MY_task_get_note(deleted_task, LIBC_NOTEPAD);
211    }
212
213    /* if (ptr) */
214    if (ptr && ptr != &libc_global_reent)
215    {
216      _wrapup_reent(ptr);
217      _reclaim_reent(ptr);
218      free(ptr);
219    }
220
221    MY_task_set_note(deleted_task, LIBC_NOTEPAD, 0);
222
223    /*
224     * Require the switch back to another task to install its own
225     */
226
227    if (current_task == deleted_task)
228    {
229      _REENT = 0;
230    }
231}
232
233/*
234 *  Function:   libc_init
235 *  Created:    94/12/10
236 *
237 *  Description:
238 *      Init libc for CYGNUS newlib
239 *      Set up _REENT to use our global libc_global_reent.
240 *      (newlib provides a global of its own, but we prefer our
241 *      own name for it)
242 *
243 *      If reentrancy is desired (which it should be), then
244 *      we install the task extension hooks to maintain the
245 *      newlib reentrancy global variable _REENT on task
246 *      create, delete, switch, exit, etc.
247 *
248 *  Parameters:
249 *      reentrant               non-zero if reentrant library desired.
250 *
251 *  Returns:
252 *
253 *  Side Effects:
254 *      installs libc extensions if reentrant.
255 *
256 *  Notes:
257 *
258 *
259 *  Deficiencies/ToDo:
260 *
261 */
262
263void
264libc_init(int reentrant)
265{
266    rtems_extensions_table  libc_extension;
267    rtems_id                extension_id;
268    rtems_status_code       rc;
269
270    _REENT = &libc_global_reent;
271
272    if (reentrant)
273    {
274        memset(&libc_extension, 0, sizeof(libc_extension));
275
276        libc_extension.thread_create  = libc_create_hook;
277        libc_extension.thread_start   = libc_start_hook;
278#ifdef NEED_SETVBUF
279        libc_extension.thread_begin   = libc_begin_hook;
280#endif
281        libc_extension.thread_switch  = libc_switch_hook;
282        libc_extension.thread_delete  = libc_delete_hook;
283
284        rc = rtems_extension_create(rtems_build_name('L', 'I', 'B', 'C'),
285                              &libc_extension, &extension_id);
286        if (rc != RTEMS_SUCCESSFUL)
287            rtems_fatal_error_occurred(rc);
288
289        libc_reentrant = reentrant;
290    }
291}
292
293#if 0
294/*
295 *  Routines required by the gnat runtime.
296 */
297
298int get_errno()
299{
300  return errno;
301}
302#endif
303
304/*
305 *  Function:   _exit
306 *  Created:    94/12/10
307 *
308 *  Description:
309 *      Called from exit() after it does atexit() processing and stdio fflush's
310 *
311 *      called from bottom of exit() to really delete the task.
312 *      If we are using reentrant libc, then let the delete extension
313 *      do all the work, otherwise if a shutdown is in progress,
314 *      then just do it.
315 *
316 *  Parameters:
317 *      exit status
318 *
319 *  Returns:
320 *      does not return
321 *
322 *  Side Effects:
323 *
324 *  Notes:
325 *
326 *
327 *  Deficiencies/ToDo:
328 *
329 *
330 */
331
332#if !defined(RTEMS_UNIX) && !defined(__GO32__)
333void _exit(int status)
334{
335    rtems_shutdown_executive(status);
336}
337
338#else
339
340void exit(int status)
341{
342    libc_wrapup();
343    rtems_shutdown_executive(status);
344}
345#endif
346
347
348/*
349 *  These are directly supported (and completely correct) in the posix api.
350 */
351
352#if !defined(RTEMS_POSIX_API)
353pid_t __getpid(void)
354{
355  return 0;
356}
357#endif
358
359#if !defined(RTEMS_POSIX_API) || defined(__GO32__)
360pid_t getpid(void)
361{
362  return __getpid();
363}
364#endif
365
366#if !defined(RTEMS_POSIX_API) || defined(__GO32__)
367int kill( pid_t pid, int sig )
368{
369  return 0;
370}
371#endif
372
373int __kill( pid_t pid, int sig )
374{
375  return 0;
376}
377
378#if !defined(RTEMS_POSIX_API)
379unsigned int sleep(
380  unsigned int seconds
381)
382{
383  rtems_status_code status;
384  rtems_interval    ticks_per_second;
385  rtems_interval    ticks;
386 
387  status = rtems_clock_get(
388    RTEMS_CLOCK_GET_TICKS_PER_SECOND,
389    &ticks_per_second
390  );
391 
392  ticks = seconds * ticks_per_second;
393 
394  status = rtems_task_wake_after( ticks );
395 
396  /*
397   *  Returns the "unslept" amount of time.  In RTEMS signals are not
398   *  interruptable, so tasks really sleep all of the requested time.
399   */
400 
401  return 0;
402}
403#endif
404
405
406#endif
Note: See TracBrowser for help on using the repository browser.