source: rtems/c/src/lib/libc/newlibc.c @ dcec5a4

4.104.114.84.95
Last change on this file since dcec5a4 was dcec5a4, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 29, 1997 at 12:29:25 AM

Merged newlib's libgloss support for rtems into this directory. This
should simplify the build process.

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