source: rtems/c/src/lib/libc/newlibc.c @ 0bf2ff8

4.104.114.84.95
Last change on this file since 0bf2ff8 was edfb0eb, checked in by Joel Sherrill <joel.sherrill@…>, on 02/18/99 at 15:11:41

GLobal reentrancy structure is now dynamically initialized.

  • Property mode set to 100644
File size: 9.8 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#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
17#include <rtems.h>
18
19#if defined(RTEMS_NEWLIB)
20#include <libcsupport.h>
21#include <stdlib.h>             /* for free() */
22#include <string.h>             /* for memset() */
23
24#include <sys/reent.h>          /* for extern of _REENT (aka _impure_ptr) */
25#include <errno.h>
26
27/*
28 *  NOTE:
29 *        There is some problem with doing this on the hpux version
30 *        of the UNIX simulator (symptom is printf core dumps), so
31 *        we just don't for now.
32 *        Not sure if this is a problem with hpux, newlib, or something else.
33 */
34 
35#if defined(RTEMS_UNIX) && !defined(hpux)
36#define NEED_SETVBUF
37#endif
38 
39#ifdef NEED_SETVBUF
40#include <stdio.h>
41#endif
42
43/*
44 *  Private routines
45 */
46
47void MY_task_set_note(
48  rtems_tcb        *tcb,
49  rtems_unsigned32 notepad,
50  rtems_unsigned32 note
51);
52
53rtems_unsigned32 MY_task_get_note(
54  rtems_tcb        *tcb,
55  rtems_unsigned32  notepad
56);
57
58
59#define LIBC_NOTEPAD RTEMS_NOTEPAD_LAST
60
61
62int              libc_reentrant;        /* do we think we are reentrant? */
63struct _reent    libc_global_reent;
64
65/*
66 * CYGNUS newlib routine that does atexit() processing and flushes
67 *      stdio streams
68 *      undocumented
69 */
70
71extern void _wrapup_reent(struct _reent *);
72extern void _reclaim_reent(struct _reent *);
73
74#include <stdio.h>
75
76void
77libc_wrapup(void)
78{
79    /*
80     *  In case RTEMS is already down, don't do this.  It could be
81     *  dangerous.
82     */
83
84    if (!_System_state_Is_up(_System_state_Get()))
85       return;
86
87    _wrapup_reent(0);
88    if (_REENT != &libc_global_reent)
89    {
90        _wrapup_reent(&libc_global_reent);
91#if 0
92        /* don't reclaim this one, just in case we do printfs */
93        /* on our way out to ROM */
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    fclose (stdin);
106    fclose (stdout);
107    fclose (stderr);
108}
109
110
111rtems_boolean
112libc_create_hook(rtems_tcb *current_task,
113                 rtems_tcb *creating_task)
114{
115    MY_task_set_note(creating_task, LIBC_NOTEPAD, 0);
116    return TRUE;
117}
118
119/*
120 * Called for all user TASKS (system tasks are MPCI Receive Server and IDLE)
121 */
122
123rtems_extension
124libc_start_hook(rtems_tcb *current_task,
125                rtems_tcb *starting_task)
126{
127    struct _reent *ptr;
128
129    /* NOTE: our malloc is reentrant without a reent ptr since
130     *  it is based on region manager
131     */
132
133    ptr = (struct _reent *) calloc(1, sizeof(struct _reent));
134
135    if (!ptr)
136       rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
137 
138#ifdef __GNUC__
139    /* GCC extension: structure constants */
140    *ptr = (struct _reent) _REENT_INIT((*ptr));
141#else
142    /*
143     *  Warning: THIS IS VERY DEPENDENT ON NEWLIB!!! WRITTEN FOR 1.7.0
144     */
145    ptr->_errno=0;
146    ptr->_stdin=&ptr->__sf[0];
147    ptr->_stdout=&ptr->__sf[1];
148    ptr->_stderr=&ptr->__sf[2];
149    ptr->_scanpoint=0;
150    ptr->_asctime[0]=0;
151    ptr->_next=1;
152    ptr->__sdidinit=0;
153#endif
154
155    MY_task_set_note(starting_task, LIBC_NOTEPAD, (rtems_unsigned32) ptr);
156}
157
158/*
159 * Called for all user TASKS (system tasks are MPCI Receive Server and IDLE)
160 */
161 
162#ifdef NEED_SETVBUF
163rtems_extension
164libc_begin_hook(rtems_tcb *current_task)
165{
166  setvbuf( stdout, NULL, _IOLBF, BUFSIZ );
167}
168#endif
169
170rtems_extension
171libc_switch_hook(rtems_tcb *current_task,
172                 rtems_tcb *heir_task)
173{
174    rtems_unsigned32 impure_value;
175
176    /* XXX We can't use rtems_task_set_note() here since SYSI task has a
177     * tid of 0, which is treated specially (optimized, actually)
178     * by rtems_task_set_note
179     *
180     * NOTE:  The above comment is no longer true and we need to use
181     *        the extension data areas added about the same time.
182     */
183
184    /*
185     *  Don't touch the outgoing task if it has been deleted.
186     */
187
188    if ( !_States_Is_transient( current_task->current_state ) ) {
189      impure_value = (rtems_unsigned32) _REENT;
190      MY_task_set_note(current_task, LIBC_NOTEPAD, impure_value);
191    }
192
193    _REENT = (struct _reent *) MY_task_get_note(heir_task, LIBC_NOTEPAD);
194
195}
196
197/*
198 *  Function:   libc_delete_hook
199 *  Created:    94/12/10
200 *
201 *  Description:
202 *      Called when a task is deleted.
203 *      Must restore the new lib reentrancy state for the new current
204 *      task.
205 *
206 *  Parameters:
207 *
208 *
209 *  Returns:
210 *
211 *
212 *  Side Effects:
213 *
214 *  Notes:
215 *
216 *
217 *  Deficiencies/ToDo:
218 *
219 *
220 */
221rtems_extension
222libc_delete_hook(rtems_tcb *current_task,
223                 rtems_tcb *deleted_task)
224{
225    struct _reent *ptr;
226
227    /*
228     * The reentrancy structure was allocated by newlib using malloc()
229     */
230
231    if (current_task == deleted_task)
232    {
233      ptr = _REENT;
234    }
235    else
236    {
237      ptr = (struct _reent *) MY_task_get_note(deleted_task, LIBC_NOTEPAD);
238    }
239
240    /* if (ptr) */
241    if (ptr && ptr != &libc_global_reent)
242    {
243      _wrapup_reent(ptr);
244      _reclaim_reent(ptr);
245      free(ptr);
246    }
247
248    MY_task_set_note(deleted_task, LIBC_NOTEPAD, 0);
249
250    /*
251     * Require the switch back to another task to install its own
252     */
253
254    if (current_task == deleted_task)
255    {
256      _REENT = 0;
257    }
258}
259
260/*
261 *  Function:   libc_init
262 *  Created:    94/12/10
263 *
264 *  Description:
265 *      Init libc for CYGNUS newlib
266 *      Set up _REENT to use our global libc_global_reent.
267 *      (newlib provides a global of its own, but we prefer our
268 *      own name for it)
269 *
270 *      If reentrancy is desired (which it should be), then
271 *      we install the task extension hooks to maintain the
272 *      newlib reentrancy global variable _REENT on task
273 *      create, delete, switch, exit, etc.
274 *
275 *  Parameters:
276 *      reentrant               non-zero if reentrant library desired.
277 *
278 *  Returns:
279 *
280 *  Side Effects:
281 *      installs libc extensions if reentrant.
282 *
283 *  Notes:
284 *
285 *
286 *  Deficiencies/ToDo:
287 *
288 */
289
290void
291libc_init(int reentrant)
292{
293    rtems_extensions_table  libc_extension;
294    rtems_id                extension_id;
295    rtems_status_code       rc;
296
297    libc_global_reent = (struct _reent) _REENT_INIT((libc_global_reent));
298    _REENT = &libc_global_reent;
299
300    if (reentrant)
301    {
302        memset(&libc_extension, 0, sizeof(libc_extension));
303
304        libc_extension.thread_create  = libc_create_hook;
305        libc_extension.thread_start   = libc_start_hook;
306#ifdef NEED_SETVBUF
307        libc_extension.thread_begin   = libc_begin_hook;
308#endif
309        libc_extension.thread_switch  = libc_switch_hook;
310        libc_extension.thread_delete  = libc_delete_hook;
311
312        rc = rtems_extension_create(rtems_build_name('L', 'I', 'B', 'C'),
313                              &libc_extension, &extension_id);
314        if (rc != RTEMS_SUCCESSFUL)
315            rtems_fatal_error_occurred( rc );
316
317        libc_reentrant = reentrant;
318    }
319}
320
321#if 0
322/*
323 *  Routines required by the gnat runtime.
324 */
325
326int get_errno()
327{
328  return errno;
329}
330#endif
331
332/*
333 *  Function:   _exit
334 *  Created:    94/12/10
335 *
336 *  Description:
337 *      Called from exit() after it does atexit() processing and stdio fflush's
338 *
339 *      called from bottom of exit() to really delete the task.
340 *      If we are using reentrant libc, then let the delete extension
341 *      do all the work, otherwise if a shutdown is in progress,
342 *      then just do it.
343 *
344 *  Parameters:
345 *      exit status
346 *
347 *  Returns:
348 *      does not return
349 *
350 *  Side Effects:
351 *
352 *  Notes:
353 *
354 *
355 *  Deficiencies/ToDo:
356 *
357 *
358 */
359
360#include <stdio.h>
361
362/* #if !defined(RTEMS_UNIX) && !defined(__GO32__) && !defined(_AM29K) */
363#if !defined(RTEMS_UNIX) && !defined(_AM29K)
364void _exit(int status)
365{
366    libc_wrapup(); /* Why? XXX */
367    rtems_shutdown_executive(status);
368}
369
370#else
371
372void exit(int status)
373{
374    libc_wrapup();
375    rtems_shutdown_executive(status);
376}
377#endif
378
379
380/*
381 *  These are directly supported (and completely correct) in the posix api.
382 */
383
384pid_t __getpid(void)
385{
386  return getpid();
387}
388
389/* #if !defined(RTEMS_POSIX_API) || defined(__GO32__) */
390#if !defined(RTEMS_POSIX_API)
391pid_t getpid(void)
392{
393  return 0;
394}
395
396pid_t _getpid_r(
397  struct _reent *ptr
398)
399{
400  return getpid();
401}
402#endif
403
404/* #if !defined(RTEMS_POSIX_API) || defined(__GO32__) */
405#if !defined(RTEMS_POSIX_API)
406int kill( pid_t pid, int sig )
407{
408  return 0;
409}
410
411int _kill_r( pid_t pid, int sig )
412{
413  return 0;
414}
415#endif
416
417int __kill( pid_t pid, int sig )
418{
419  return 0;
420}
421
422#if !defined(RTEMS_POSIX_API)
423unsigned int sleep(
424  unsigned int seconds
425)
426{
427  rtems_status_code status;
428  rtems_interval    ticks_per_second;
429  rtems_interval    ticks;
430 
431  status = rtems_clock_get(
432    RTEMS_CLOCK_GET_TICKS_PER_SECOND,
433    &ticks_per_second
434  );
435 
436  ticks = seconds * ticks_per_second;
437 
438  status = rtems_task_wake_after( ticks );
439 
440  /*
441   *  Returns the "unslept" amount of time.  In RTEMS signals are not
442   *  interruptable, so tasks really sleep all of the requested time.
443   */
444 
445  return 0;
446}
447#endif
448
449
450/*
451 *  Newlib Interface Support
452 *
453 *  Routines to Access Internal RTEMS Resources without violating
454 *  kernel visibility.
455 *
456 */
457
458void MY_task_set_note(
459  Thread_Control *the_thread,
460  unsigned32      notepad,
461  unsigned32      note
462)
463{
464  RTEMS_API_Control    *api;
465 
466  api = the_thread->API_Extensions[ THREAD_API_RTEMS ];
467
468  if ( api )
469    api->Notepads[ notepad ] = note;
470}
471
472
473unsigned32 MY_task_get_note(
474  Thread_Control *the_thread,
475  unsigned32      notepad
476)
477{
478  RTEMS_API_Control    *api;
479 
480  api = the_thread->API_Extensions[ THREAD_API_RTEMS ];
481
482  return api->Notepads[ notepad ];
483}
484
485void *MY_CPU_Context_FP_start(
486  void       *base,
487  unsigned32  offset
488)
489{
490  return _CPU_Context_Fp_start( base, offset );
491}
492#endif
Note: See TracBrowser for help on using the repository browser.