source: rtems/c/src/exec/libcsupport/src/newlibc.c @ 443f26d2

4.104.114.84.95
Last change on this file since 443f26d2 was fb327db3, checked in by Joel Sherrill <joel.sherrill@…>, on 09/22/00 at 20:35:12

2000-09-22 Joel Sherrill <joel@…>

  • libc/newlibc.c: Removed _A29K specific ifdef.
  • 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)
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.