source: rtems/c/src/lib/libc/newlibc.c @ 1442144d

4.104.114.84.95
Last change on this file since 1442144d was 9c49db4, checked in by Joel Sherrill <joel.sherrill@…>, on 01/08/01 at 18:26:44

2001-01-08 Ralf Corsepius <corsepiu@…>

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