source: rtems/c/src/lib/libc/newlibc.c @ 5a23ca84

4.104.114.84.95
Last change on this file since 5a23ca84 was 7edb9281, checked in by Joel Sherrill <joel.sherrill@…>, on 11/05/99 at 19:02:03

Following comments from Eric Norum <eric@…>, a fairly
substantial upgrade of newlibc.c occurred. Now the user extension
data area is used rather than notepads and as many routines as possible
were split into other files further reducing the minimum footprint
of an RTEMS executable.

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/*
2 *  Implementation of hooks for the CYGNUS newlib libc
3 *  These hooks set things up so that:
4 *       + '_REENT' is switched at task switch time.
5 *
6 *  COPYRIGHT (c) 1994 by Division Incorporated
7 *
8 *  The license and distribution terms for this file may be
9 *  found in the file LICENSE in this distribution or at
10 *  http://www.OARcorp.com/rtems/license.html.
11 *
12 *  $Id$
13 *
14 */
15
16#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
17#include <rtems.h>
18
19#if defined(RTEMS_NEWLIB)
20#include <libcsupport.h>
21#include <stdlib.h>             /* for free() */
22#include <string.h>             /* for memset() */
23
24#include <sys/reent.h>          /* for extern of _REENT (aka _impure_ptr) */
25#include <errno.h>
26
27/*
28 *  NOTE:
29 *        There is some problem with doing this on the hpux version
30 *        of the UNIX simulator (symptom is printf core dumps), so
31 *        we just don't for now.
32 *        Not sure if this is a problem with hpux, newlib, or something else.
33 */
34 
35#if defined(RTEMS_UNIX) && !defined(hpux)
36#define NEED_SETVBUF
37#endif
38 
39#ifdef NEED_SETVBUF
40#include <stdio.h>
41#endif
42
43static int extension_index;
44
45/*
46 *  Private routines
47 */
48
49#define set_newlib_extension( _the_thread, _value ) \
50  (_the_thread)->extensions[ extension_index ] = (_value);
51
52#define get_newlib_extension( _the_thread ) \
53  (_the_thread)->extensions[ extension_index ]
54
55int              libc_reentrant;        /* do we think we are reentrant? */
56struct _reent    libc_global_reent;
57
58/*
59 * CYGNUS newlib routine that does atexit() processing and flushes
60 *      stdio streams
61 *      undocumented
62 */
63
64extern void _wrapup_reent(struct _reent *);
65extern void _reclaim_reent(struct _reent *);
66
67#include <stdio.h>
68
69void libc_wrapup(void)
70{
71  /*
72   *  In case RTEMS is already down, don't do this.  It could be
73   *  dangerous.
74   */
75
76  if (!_System_state_Is_up(_System_state_Get()))
77     return;
78
79  /*
80   *  This was already done if the user called exit() directly .
81  _wrapup_reent(0);
82   */
83
84  if (_REENT != &libc_global_reent) {
85      _wrapup_reent(&libc_global_reent);
86#if 0
87      /*  Don't reclaim this one, just in case we do printfs
88       *  on the way out to ROM.
89       */
90      _reclaim_reent(&libc_global_reent);
91#endif
92      _REENT = &libc_global_reent;
93  }
94 
95  /*
96   * Try to drain output buffers.
97   *
98   * Should this be changed to do *all* file streams?
99   *    _fwalk (_REENT, fclose);
100   */
101
102  fclose (stdin);
103  fclose (stdout);
104  fclose (stderr);
105}
106
107
108rtems_boolean libc_create_hook(
109  rtems_tcb *current_task,
110  rtems_tcb *creating_task
111)
112{
113  set_newlib_extension( creating_task, NULL );
114  return TRUE;
115}
116
117/*
118 * Called for all user TASKS (system tasks are MPCI Receive Server and IDLE)
119 */
120
121rtems_extension libc_start_hook(
122  rtems_tcb *current_task,
123  rtems_tcb *starting_task
124)
125{
126  struct _reent *ptr;
127
128  /*  NOTE: The RTEMS malloc is reentrant without a reent ptr since
129   *        it is based on the Classic API Region Manager.
130   */
131
132  ptr = (struct _reent *) calloc(1, sizeof(struct _reent));
133
134  if (!ptr)
135     rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
136 
137#ifdef __GNUC__
138  /* GCC extension: structure constants */
139  *ptr = (struct _reent) _REENT_INIT((*ptr));
140#else
141  /*
142   *  WARNING: THIS IS VERY DEPENDENT ON NEWLIB!!!
143   *           Last visual check was against newlib 1.8.2 but last known
144   *           use was against 1.7.0.  This is basically an exansion of
145   *           REENT_INIT() in <sys/reent.h>.
146   *  NOTE:    calloc() takes care of zeroing fields.
147   */
148  ptr->_stdin = &ptr->__sf[0];
149  ptr->_stdout = &ptr->__sf[1];
150  ptr->_stderr = &ptr->__sf[2];
151  ptr->_current_locale = "C";
152  ptr->_new._reent._rand_next = 1;
153#endif
154
155  set_newlib_extension( starting_task, ptr );
156}
157
158/*
159 * Called for all user TASKS (system tasks are MPCI Receive Server and IDLE)
160 */
161 
162#ifdef NEED_SETVBUF
163rtems_extension libc_begin_hook(rtems_tcb *current_task)
164{
165  setvbuf( stdout, NULL, _IOLBF, BUFSIZ );
166}
167#endif
168
169rtems_extension libc_switch_hook(
170  rtems_tcb *current_task,
171  rtems_tcb *heir_task
172)
173{
174  /*
175   *  Don't touch the outgoing task if it has been deleted.
176   */
177
178  if ( !_States_Is_transient( current_task->current_state ) ) {
179    set_newlib_extension( current_task, _REENT );
180  }
181
182  _REENT = (struct _reent *) get_newlib_extension( heir_task );
183}
184
185/*
186 *  Function:   libc_delete_hook
187 *  Created:    94/12/10
188 *
189 *  Description:
190 *      Called when a task is deleted.
191 *      Must restore the new lib reentrancy state for the new current
192 *      task.
193 *
194 *  Parameters:
195 *
196 *
197 *  Returns:
198 *
199 *
200 *  Side Effects:
201 *
202 *  Notes:
203 *
204 *
205 *  Deficiencies/ToDo:
206 *
207 *
208 */
209
210rtems_extension libc_delete_hook(
211  rtems_tcb *current_task,
212  rtems_tcb *deleted_task
213)
214{
215  struct _reent *ptr;
216
217  /*
218   * The reentrancy structure was allocated by newlib using malloc()
219   */
220
221  if (current_task == deleted_task) {
222    ptr = _REENT;
223  } else {
224    ptr = (struct _reent *) get_newlib_extension( deleted_task );
225  }
226
227  /* if (ptr) */
228  if (ptr && ptr != &libc_global_reent) {
229    _wrapup_reent(ptr);
230    _reclaim_reent(ptr);
231    free(ptr);
232  }
233
234  set_newlib_extension( deleted_task, NULL );
235
236  /*
237   * Require the switch back to another task to install its own
238   */
239
240  if ( current_task == deleted_task ) {
241    _REENT = 0;
242  }
243}
244
245/*
246 *  Function:   libc_init
247 *  Created:    94/12/10
248 *
249 *  Description:
250 *      Init libc for CYGNUS newlib
251 *      Set up _REENT to use our global libc_global_reent.
252 *      (newlib provides a global of its own, but we prefer our
253 *      own name for it)
254 *
255 *      If reentrancy is desired (which it should be), then
256 *      we install the task extension hooks to maintain the
257 *      newlib reentrancy global variable _REENT on task
258 *      create, delete, switch, exit, etc.
259 *
260 *  Parameters:
261 *      reentrant               non-zero if reentrant library desired.
262 *
263 *  Returns:
264 *
265 *  Side Effects:
266 *      installs libc extensions if reentrant.
267 *
268 *  Notes:
269 *
270 *
271 *  Deficiencies/ToDo:
272 *
273 */
274
275void
276libc_init(int reentrant)
277{
278  rtems_extensions_table  libc_extension;
279  rtems_status_code       rc;
280  rtems_id                extension_id;
281
282  libc_global_reent = (struct _reent) _REENT_INIT((libc_global_reent));
283  _REENT = &libc_global_reent;
284
285  if (reentrant) {
286    memset(&libc_extension, 0, sizeof(libc_extension));
287
288    libc_extension.thread_create  = libc_create_hook;
289    libc_extension.thread_start   = libc_start_hook;
290#ifdef NEED_SETVBUF
291    libc_extension.thread_begin   = libc_begin_hook;
292#endif
293    libc_extension.thread_switch  = libc_switch_hook;
294    libc_extension.thread_delete  = libc_delete_hook;
295
296    rc = rtems_extension_create(rtems_build_name('L', 'I', 'B', 'C'),
297                          &libc_extension, &extension_id);
298    if (rc != RTEMS_SUCCESSFUL)
299      rtems_fatal_error_occurred( rc );
300
301    libc_reentrant = reentrant;
302    extension_index = rtems_get_index( extension_id );
303  }
304}
305
306/*
307 *  Function:   _exit
308 *  Created:    94/12/10
309 *
310 *  Description:
311 *      Called from exit() after it does atexit() processing and stdio fflush's
312 *
313 *      called from bottom of exit() to really delete the task.
314 *      If we are using reentrant libc, then let the delete extension
315 *      do all the work, otherwise if a shutdown is in progress,
316 *      then just do it.
317 *
318 *  Parameters:
319 *      exit status
320 *
321 *  Returns:
322 *      does not return
323 *
324 *  Side Effects:
325 *
326 *  Notes:
327 *
328 *
329 *  Deficiencies/ToDo:
330 *
331 *
332 */
333
334#include <stdio.h>
335
336#if !defined(RTEMS_UNIX) && !defined(_AM29K)
337void _exit(int status)
338{
339  /*
340   *  We need to do the exit processing on the global reentrancy structure.
341   *  This has already been done on the per task reentrancy structure
342   *  associated with this task.
343   */
344
345  libc_wrapup();
346  rtems_shutdown_executive(status);
347}
348
349#else
350
351void exit(int status)
352{
353  libc_wrapup();
354  rtems_shutdown_executive(status);
355}
356#endif
357
358
359#endif
Note: See TracBrowser for help on using the repository browser.