source: rtems/cpukit/libcsupport/src/newlibc.c @ 6cff0f8

4.104.114.84.95
Last change on this file since 6cff0f8 was 6cff0f8, checked in by Joel Sherrill <joel.sherrill@…>, on 10/02/03 at 12:39:05

2003-10-02 Phil Torre <ptorre@…>

PR 504/rtems

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