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

4.104.114.84.95
Last change on this file since c9a4da01 was c9a4da01, checked in by Joel Sherrill <joel.sherrill@…>, on 11/26/03 at 17:53:30

2003-11-26 Joel Sherrill <joel@…>

PR 524/filesystem

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