source: rtems/cpukit/libcsupport/src/newlibc.c @ 8d7a1d76

4.104.114.84.95
Last change on this file since 8d7a1d76 was 8d7a1d76, checked in by Joel Sherrill <joel.sherrill@…>, on 06/18/96 at 19:06:58

minor changes to insure the few posix-ish routines needed in non-posix
mode have stubs.

  • Property mode set to 100644
File size: 8.9 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 *) malloc(sizeof(struct _reent));
118
119    /* GCC extension: structure constants */
120    *ptr = (struct _reent) _REENT_INIT((*ptr));
121
122    MY_task_set_note(starting_task, LIBC_NOTEPAD, (rtems_unsigned32) ptr);
123}
124
125/*
126 * Called for all user TASKS (system tasks are MPCI Receive Server and IDLE)
127 *
128 *  NOTE: When using RTEMS fake stat, fstat, and isatty, all output
129 *        is line buffered so this setvbuf is not necessary.  This
130 *        setvbuf insures that we can redirect the output of a test
131 *        on the UNIX simulator and it is in the same order as for a
132 *        real target.
133 */
134 
135#ifdef NEED_SETVBUF
136rtems_extension
137libc_begin_hook(rtems_tcb *current_task)
138{
139  setvbuf( stdout, NULL, _IOLBF, BUFSIZ );
140}
141#endif
142
143rtems_extension
144libc_switch_hook(rtems_tcb *current_task,
145                 rtems_tcb *heir_task)
146{
147    rtems_unsigned32 impure_value;
148
149    /* XXX We can't use rtems_task_set_note() here since SYSI task has a
150     * tid of 0, which is treated specially (optimized, actually)
151     * by rtems_task_set_note
152     *
153     * NOTE:  The above comment is no longer true and we need to use
154     *        the extension data areas added about the same time.
155     */
156
157    /*
158     *  Don't touch the outgoing task if it has been deleted.
159     */
160
161    if ( !_States_Is_transient( current_task->current_state ) ) {
162      impure_value = (rtems_unsigned32) _REENT;
163      MY_task_set_note(current_task, LIBC_NOTEPAD, impure_value);
164    }
165
166    _REENT = (struct _reent *) MY_task_get_note(heir_task, LIBC_NOTEPAD);
167
168}
169
170/*
171 *  Function:   libc_delete_hook
172 *  Created:    94/12/10
173 *
174 *  Description:
175 *      Called when a task is deleted.
176 *      Must restore the new lib reentrancy state for the new current
177 *      task.
178 *
179 *  Parameters:
180 *
181 *
182 *  Returns:
183 *
184 *
185 *  Side Effects:
186 *
187 *  Notes:
188 *
189 *
190 *  Deficiencies/ToDo:
191 *
192 *
193 */
194rtems_extension
195libc_delete_hook(rtems_tcb *current_task,
196                 rtems_tcb *deleted_task)
197{
198    struct _reent *ptr;
199
200    /*
201     * The reentrancy structure was allocated by newlib using malloc()
202     */
203
204    if (current_task == deleted_task)
205    {
206      ptr = _REENT;
207    }
208    else
209    {
210      ptr = (struct _reent *) MY_task_get_note(deleted_task, LIBC_NOTEPAD);
211    }
212
213    /* if (ptr) */
214    if (ptr && ptr != &libc_global_reent)
215    {
216      _wrapup_reent(ptr);
217      _reclaim_reent(ptr);
218      free(ptr);
219    }
220
221    MY_task_set_note(deleted_task, LIBC_NOTEPAD, 0);
222
223    /*
224     * Require the switch back to another task to install its own
225     */
226
227    if (current_task == deleted_task)
228    {
229      _REENT = 0;
230    }
231}
232
233/*
234 *  Function:   libc_init
235 *  Created:    94/12/10
236 *
237 *  Description:
238 *      Init libc for CYGNUS newlib
239 *      Set up _REENT to use our global libc_global_reent.
240 *      (newlib provides a global of its own, but we prefer our
241 *      own name for it)
242 *
243 *      If reentrancy is desired (which it should be), then
244 *      we install the task extension hooks to maintain the
245 *      newlib reentrancy global variable _REENT on task
246 *      create, delete, switch, exit, etc.
247 *
248 *  Parameters:
249 *      reentrant               non-zero if reentrant library desired.
250 *
251 *  Returns:
252 *
253 *  Side Effects:
254 *      installs libc extensions if reentrant.
255 *
256 *  Notes:
257 *
258 *
259 *  Deficiencies/ToDo:
260 *
261 */
262
263void
264libc_init(int reentrant)
265{
266    rtems_extensions_table  libc_extension;
267    rtems_id                extension_id;
268    rtems_status_code       rc;
269
270    _REENT = &libc_global_reent;
271
272    if (reentrant)
273    {
274        memset(&libc_extension, 0, sizeof(libc_extension));
275
276        libc_extension.thread_create  = libc_create_hook;
277        libc_extension.thread_start   = libc_start_hook;
278#ifdef NEED_SETVBUF
279        libc_extension.thread_begin   = libc_begin_hook;
280#endif
281        libc_extension.thread_switch  = libc_switch_hook;
282        libc_extension.thread_delete  = libc_delete_hook;
283
284        rc = rtems_extension_create(rtems_build_name('L', 'I', 'B', 'C'),
285                              &libc_extension, &extension_id);
286        if (rc != RTEMS_SUCCESSFUL)
287            rtems_fatal_error_occurred(rc);
288
289        libc_reentrant = reentrant;
290    }
291}
292
293/*
294 *  Routines required by the gnat runtime.
295 */
296
297int get_errno()
298{
299  return errno;
300}
301
302/*
303 *  Function:   _exit
304 *  Created:    94/12/10
305 *
306 *  Description:
307 *      Called from exit() after it does atexit() processing and stdio fflush's
308 *
309 *      called from bottom of exit() to really delete the task.
310 *      If we are using reentrant libc, then let the delete extension
311 *      do all the work, otherwise if a shutdown is in progress,
312 *      then just do it.
313 *
314 *  Parameters:
315 *      exit status
316 *
317 *  Returns:
318 *      does not return
319 *
320 *  Side Effects:
321 *
322 *  Notes:
323 *
324 *
325 *  Deficiencies/ToDo:
326 *
327 *
328 */
329
330#if !defined(RTEMS_UNIX) && !defined(__GO32__)
331void _exit(int status)
332{
333    rtems_shutdown_executive(status);
334}
335
336#else
337
338void exit(int status)
339{
340    libc_wrapup();
341    rtems_shutdown_executive(status);
342}
343#endif
344
345
346/*
347 *  These are directly supported (and completely correct) in the posix api.
348 */
349
350#if !defined(__RTEMS_POSIX_API__)
351
352pid_t __getpid(void)
353{
354  return 0;
355}
356#endif
357
358#if !defined(__RTEMS_POSIX_API__) && !defined(__GO32__)
359pid_t getpid(void)
360{
361  return __getpid();
362}
363#endif
364
365#if !defined(__RTEMS_POSIX_API__) && !defined(__GO32__)
366int kill( pid_t pid, int sig )
367{
368  return 0;
369}
370#endif
371
372int __kill( pid_t pid, int sig )
373{
374  return 0;
375}
376
377unsigned int sleep(
378  unsigned int seconds
379)
380{
381  rtems_status_code status;
382  rtems_interval    ticks_per_second;
383  rtems_interval    ticks;
384 
385  status = rtems_clock_get(
386    RTEMS_CLOCK_GET_TICKS_PER_SECOND,
387    &ticks_per_second
388  );
389 
390  ticks = seconds * ticks_per_second;
391 
392  status = rtems_task_wake_after( ticks );
393 
394  /*
395   *  Returns the "unslept" amount of time.  In RTEMS signals are not
396   *  interruptable, so tasks really sleep all of the requested time.
397   */
398 
399  return 0;
400}
401
402
403#endif
Note: See TracBrowser for help on using the repository browser.