source: rtems/cpukit/libcsupport/src/newlibc.c @ f26145b

4.104.114.84.95
Last change on this file since f26145b was 50f32b11, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/18/04 at 06:05:35

Remove stray white spaces.

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