source: rtems/c/src/lib/libc/newlibc.c @ 0836603

4.104.114.84.95
Last change on this file since 0836603 was 5e9a594, checked in by Joel Sherrill <joel.sherrill@…>, on 09/18/96 at 20:53:35

modified to support non-GNU compilers and to use calloc rather than
malloc for per-thread reentrancy structure allocation.

  • Property mode set to 100644
File size: 9.3 KB
Line 
1#if defined(RTEMS_NEWLIB)
2
3/*
4 *  COPYRIGHT (c) 1994 by Division Incorporated
5 *
6 *  To anyone who acknowledges that this file is provided "AS IS"
7 *  without any express or implied warranty:
8 *      permission to use, copy, modify, and distribute this file
9 *      for any purpose is hereby granted without fee, provided that
10 *      the above copyright notice and this notice appears in all
11 *      copies, and that the name of Division Incorporated not be
12 *      used in advertising or publicity pertaining to distribution
13 *      of the software without specific, written prior permission.
14 *      Division Incorporated makes no representations about the
15 *      suitability of this software for any purpose.
16 *
17 *  Description:
18 *      Implementation of hooks for the CYGNUS newlib libc
19 *      These hooks set things up so that:
20 *              '_REENT' is switched at task switch time.
21 *
22 *
23 *  TODO:
24 *
25 *  NOTE:
26 *
27 *  $Id$
28 *
29 */
30
31#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
32#include <rtems.h>
33#include <libcsupport.h>
34#include <stdlib.h>             /* for free() */
35#include <string.h>             /* for memset() */
36
37#include <sys/reent.h>          /* for extern of _REENT (aka _impure_ptr) */
38#include <errno.h>
39
40/*
41 *  NOTE: When using RTEMS fake stat, fstat, and isatty, all output
42 *        is line buffered so this setvbuf is not necessary.  This
43 *        setvbuf insures that we can redirect the output of a test
44 *        on the UNIX simulator and it is in the same order as for a
45 *        real target.
46 *  NOTE:
47 *        There is some problem with doing this on the hpux version
48 *        of the UNIX simulator (symptom is printf core dumps), so
49 *        we just don't for now.
50 *        Not sure if this is a problem with hpux, newlib, or something else.
51 */
52 
53#if defined(RTEMS_UNIX) && !defined(hpux)
54#define NEED_SETVBUF
55#endif
56 
57#ifdef NEED_SETVBUF
58#include <stdio.h>
59#endif
60
61#include "internal.h"
62
63#define LIBC_NOTEPAD RTEMS_NOTEPAD_LAST
64
65
66int              libc_reentrant;        /* do we think we are reentrant? */
67struct _reent    libc_global_reent = _REENT_INIT(libc_global_reent);
68
69/*
70 * CYGNUS newlib routine that does atexit() processing and flushes
71 *      stdio streams
72 *      undocumented
73 */
74
75extern void _wrapup_reent(struct _reent *);
76extern void _reclaim_reent(struct _reent *);
77
78void
79libc_wrapup(void)
80{
81    _wrapup_reent(0);
82    if (_REENT != &libc_global_reent)
83    {
84        _wrapup_reent(&libc_global_reent);
85#if 0
86        /* don't reclaim this one, just in case we do printfs */
87        /* on our way out to ROM */
88        _reclaim_reent(&libc_global_reent);
89#endif
90        _REENT = &libc_global_reent;
91    }
92}
93
94
95rtems_boolean
96libc_create_hook(rtems_tcb *current_task,
97                 rtems_tcb *creating_task)
98{
99    MY_task_set_note(creating_task, LIBC_NOTEPAD, 0);
100    return TRUE;
101}
102
103/*
104 * Called for all user TASKS (system tasks are MPCI Receive Server and IDLE)
105 */
106
107rtems_extension
108libc_start_hook(rtems_tcb *current_task,
109                rtems_tcb *starting_task)
110{
111    struct _reent *ptr;
112
113    /* NOTE: our malloc is reentrant without a reent ptr since
114     *  it is based on region manager
115     */
116
117    ptr = (struct _reent *) calloc(1, sizeof(struct _reent));
118
119    if (!ptr)
120       rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
121 
122#ifdef __GNUC__
123    /* GCC extension: structure constants */
124    *ptr = (struct _reent) _REENT_INIT((*ptr));
125#else
126    /*
127     *  Warning: THIS IS VERY DEPENDENT ON NEWLIB!!! WRITTEN FOR 1.7.0
128     */
129    ptr->_errno=0;
130    ptr->_stdin=&ptr->__sf[0];
131    ptr->_stdout=&ptr->__sf[1];
132    ptr->_stderr=&ptr->__sf[2];
133    ptr->_scanpoint=0;
134    ptr->_asctime[0]=0;
135    ptr->_next=1;
136    ptr->__sdidinit=0;
137#endif
138
139    MY_task_set_note(starting_task, LIBC_NOTEPAD, (rtems_unsigned32) ptr);
140}
141
142/*
143 * Called for all user TASKS (system tasks are MPCI Receive Server and IDLE)
144 *
145 *  NOTE: When using RTEMS fake stat, fstat, and isatty, all output
146 *        is line buffered so this setvbuf is not necessary.  This
147 *        setvbuf insures that we can redirect the output of a test
148 *        on the UNIX simulator and it is in the same order as for a
149 *        real target.
150 */
151 
152#ifdef NEED_SETVBUF
153rtems_extension
154libc_begin_hook(rtems_tcb *current_task)
155{
156  setvbuf( stdout, NULL, _IOLBF, BUFSIZ );
157}
158#endif
159
160rtems_extension
161libc_switch_hook(rtems_tcb *current_task,
162                 rtems_tcb *heir_task)
163{
164    rtems_unsigned32 impure_value;
165
166    /* XXX We can't use rtems_task_set_note() here since SYSI task has a
167     * tid of 0, which is treated specially (optimized, actually)
168     * by rtems_task_set_note
169     *
170     * NOTE:  The above comment is no longer true and we need to use
171     *        the extension data areas added about the same time.
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      impure_value = (rtems_unsigned32) _REENT;
180      MY_task_set_note(current_task, LIBC_NOTEPAD, impure_value);
181    }
182
183    _REENT = (struct _reent *) MY_task_get_note(heir_task, LIBC_NOTEPAD);
184
185}
186
187/*
188 *  Function:   libc_delete_hook
189 *  Created:    94/12/10
190 *
191 *  Description:
192 *      Called when a task is deleted.
193 *      Must restore the new lib reentrancy state for the new current
194 *      task.
195 *
196 *  Parameters:
197 *
198 *
199 *  Returns:
200 *
201 *
202 *  Side Effects:
203 *
204 *  Notes:
205 *
206 *
207 *  Deficiencies/ToDo:
208 *
209 *
210 */
211rtems_extension
212libc_delete_hook(rtems_tcb *current_task,
213                 rtems_tcb *deleted_task)
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    {
223      ptr = _REENT;
224    }
225    else
226    {
227      ptr = (struct _reent *) MY_task_get_note(deleted_task, LIBC_NOTEPAD);
228    }
229
230    /* if (ptr) */
231    if (ptr && ptr != &libc_global_reent)
232    {
233      _wrapup_reent(ptr);
234      _reclaim_reent(ptr);
235      free(ptr);
236    }
237
238    MY_task_set_note(deleted_task, LIBC_NOTEPAD, 0);
239
240    /*
241     * Require the switch back to another task to install its own
242     */
243
244    if (current_task == deleted_task)
245    {
246      _REENT = 0;
247    }
248}
249
250/*
251 *  Function:   libc_init
252 *  Created:    94/12/10
253 *
254 *  Description:
255 *      Init libc for CYGNUS newlib
256 *      Set up _REENT to use our global libc_global_reent.
257 *      (newlib provides a global of its own, but we prefer our
258 *      own name for it)
259 *
260 *      If reentrancy is desired (which it should be), then
261 *      we install the task extension hooks to maintain the
262 *      newlib reentrancy global variable _REENT on task
263 *      create, delete, switch, exit, etc.
264 *
265 *  Parameters:
266 *      reentrant               non-zero if reentrant library desired.
267 *
268 *  Returns:
269 *
270 *  Side Effects:
271 *      installs libc extensions if reentrant.
272 *
273 *  Notes:
274 *
275 *
276 *  Deficiencies/ToDo:
277 *
278 */
279
280void
281libc_init(int reentrant)
282{
283    rtems_extensions_table  libc_extension;
284    rtems_id                extension_id;
285    rtems_status_code       rc;
286
287    _REENT = &libc_global_reent;
288
289    if (reentrant)
290    {
291        memset(&libc_extension, 0, sizeof(libc_extension));
292
293        libc_extension.thread_create  = libc_create_hook;
294        libc_extension.thread_start   = libc_start_hook;
295#ifdef NEED_SETVBUF
296        libc_extension.thread_begin   = libc_begin_hook;
297#endif
298        libc_extension.thread_switch  = libc_switch_hook;
299        libc_extension.thread_delete  = libc_delete_hook;
300
301        rc = rtems_extension_create(rtems_build_name('L', 'I', 'B', 'C'),
302                              &libc_extension, &extension_id);
303        if (rc != RTEMS_SUCCESSFUL)
304            rtems_fatal_error_occurred(rc);
305
306        libc_reentrant = reentrant;
307    }
308}
309
310#if 0
311/*
312 *  Routines required by the gnat runtime.
313 */
314
315int get_errno()
316{
317  return errno;
318}
319#endif
320
321/*
322 *  Function:   _exit
323 *  Created:    94/12/10
324 *
325 *  Description:
326 *      Called from exit() after it does atexit() processing and stdio fflush's
327 *
328 *      called from bottom of exit() to really delete the task.
329 *      If we are using reentrant libc, then let the delete extension
330 *      do all the work, otherwise if a shutdown is in progress,
331 *      then just do it.
332 *
333 *  Parameters:
334 *      exit status
335 *
336 *  Returns:
337 *      does not return
338 *
339 *  Side Effects:
340 *
341 *  Notes:
342 *
343 *
344 *  Deficiencies/ToDo:
345 *
346 *
347 */
348
349#if !defined(RTEMS_UNIX) && !defined(__GO32__) && !defined(_AM29K)
350void _exit(int status)
351{
352    rtems_shutdown_executive(status);
353}
354
355#else
356
357void exit(int status)
358{
359    libc_wrapup();
360    rtems_shutdown_executive(status);
361}
362#endif
363
364
365/*
366 *  These are directly supported (and completely correct) in the posix api.
367 */
368
369#if !defined(RTEMS_POSIX_API)
370pid_t __getpid(void)
371{
372  return 0;
373}
374#endif
375
376#if !defined(RTEMS_POSIX_API) || defined(__GO32__)
377pid_t getpid(void)
378{
379  return __getpid();
380}
381#endif
382
383#if !defined(RTEMS_POSIX_API) || defined(__GO32__)
384int kill( pid_t pid, int sig )
385{
386  return 0;
387}
388#endif
389
390int __kill( pid_t pid, int sig )
391{
392  return 0;
393}
394
395#if !defined(RTEMS_POSIX_API)
396unsigned int sleep(
397  unsigned int seconds
398)
399{
400  rtems_status_code status;
401  rtems_interval    ticks_per_second;
402  rtems_interval    ticks;
403 
404  status = rtems_clock_get(
405    RTEMS_CLOCK_GET_TICKS_PER_SECOND,
406    &ticks_per_second
407  );
408 
409  ticks = seconds * ticks_per_second;
410 
411  status = rtems_task_wake_after( ticks );
412 
413  /*
414   *  Returns the "unslept" amount of time.  In RTEMS signals are not
415   *  interruptable, so tasks really sleep all of the requested time.
416   */
417 
418  return 0;
419}
420#endif
421
422
423#endif
Note: See TracBrowser for help on using the repository browser.