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

4.104.114.84.95
Last change on this file since f00d7ad was f00d7ad, checked in by Joel Sherrill <joel.sherrill@…>, on Feb 3, 1998 at 6:30:05 PM

Added call to libc_wrapup() in _exit. This fixes a problem where
the atexit routines on the global reentrancy structure were not
invoked. But it does not seem like a 100% correct solution.

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