source: rtems/cpukit/libcsupport/src/newlibc.c @ 7e2a525b

4.104.114.84.95
Last change on this file since 7e2a525b was 7e2a525b, checked in by Joel Sherrill <joel.sherrill@…>, on 02/15/99 at 18:56:08

Patch from Eric Valette <valette@…> to undo the patch
that added ifdef on the pc386.

  • 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 = _REENT_INIT(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    _REENT = &libc_global_reent;
298
299    if (reentrant)
300    {
301        memset(&libc_extension, 0, sizeof(libc_extension));
302
303        libc_extension.thread_create  = libc_create_hook;
304        libc_extension.thread_start   = libc_start_hook;
305#ifdef NEED_SETVBUF
306        libc_extension.thread_begin   = libc_begin_hook;
307#endif
308        libc_extension.thread_switch  = libc_switch_hook;
309        libc_extension.thread_delete  = libc_delete_hook;
310
311        rc = rtems_extension_create(rtems_build_name('L', 'I', 'B', 'C'),
312                              &libc_extension, &extension_id);
313        if (rc != RTEMS_SUCCESSFUL)
314            rtems_fatal_error_occurred( rc );
315
316        libc_reentrant = reentrant;
317    }
318}
319
320#if 0
321/*
322 *  Routines required by the gnat runtime.
323 */
324
325int get_errno()
326{
327  return errno;
328}
329#endif
330
331/*
332 *  Function:   _exit
333 *  Created:    94/12/10
334 *
335 *  Description:
336 *      Called from exit() after it does atexit() processing and stdio fflush's
337 *
338 *      called from bottom of exit() to really delete the task.
339 *      If we are using reentrant libc, then let the delete extension
340 *      do all the work, otherwise if a shutdown is in progress,
341 *      then just do it.
342 *
343 *  Parameters:
344 *      exit status
345 *
346 *  Returns:
347 *      does not return
348 *
349 *  Side Effects:
350 *
351 *  Notes:
352 *
353 *
354 *  Deficiencies/ToDo:
355 *
356 *
357 */
358
359#include <stdio.h>
360
361/* #if !defined(RTEMS_UNIX) && !defined(__GO32__) && !defined(_AM29K) */
362#if !defined(RTEMS_UNIX) && !defined(_AM29K)
363void _exit(int status)
364{
365    libc_wrapup(); /* Why? XXX */
366    rtems_shutdown_executive(status);
367}
368
369#else
370
371void exit(int status)
372{
373    libc_wrapup();
374    rtems_shutdown_executive(status);
375}
376#endif
377
378
379/*
380 *  These are directly supported (and completely correct) in the posix api.
381 */
382
383pid_t __getpid(void)
384{
385  return getpid();
386}
387
388/* #if !defined(RTEMS_POSIX_API) || defined(__GO32__) */
389#if !defined(RTEMS_POSIX_API)
390pid_t getpid(void)
391{
392  return 0;
393}
394
395pid_t _getpid_r(
396  struct _reent *ptr
397)
398{
399  return getpid();
400}
401#endif
402
403/* #if !defined(RTEMS_POSIX_API) || defined(__GO32__) */
404#if !defined(RTEMS_POSIX_API)
405int kill( pid_t pid, int sig )
406{
407  return 0;
408}
409
410int _kill_r( pid_t pid, int sig )
411{
412  return 0;
413}
414#endif
415
416int __kill( pid_t pid, int sig )
417{
418  return 0;
419}
420
421#if !defined(RTEMS_POSIX_API)
422unsigned int sleep(
423  unsigned int seconds
424)
425{
426  rtems_status_code status;
427  rtems_interval    ticks_per_second;
428  rtems_interval    ticks;
429 
430  status = rtems_clock_get(
431    RTEMS_CLOCK_GET_TICKS_PER_SECOND,
432    &ticks_per_second
433  );
434 
435  ticks = seconds * ticks_per_second;
436 
437  status = rtems_task_wake_after( ticks );
438 
439  /*
440   *  Returns the "unslept" amount of time.  In RTEMS signals are not
441   *  interruptable, so tasks really sleep all of the requested time.
442   */
443 
444  return 0;
445}
446#endif
447
448
449/*
450 *  Newlib Interface Support
451 *
452 *  Routines to Access Internal RTEMS Resources without violating
453 *  kernel visibility.
454 *
455 */
456
457void MY_task_set_note(
458  Thread_Control *the_thread,
459  unsigned32      notepad,
460  unsigned32      note
461)
462{
463  RTEMS_API_Control    *api;
464 
465  api = the_thread->API_Extensions[ THREAD_API_RTEMS ];
466
467  if ( api )
468    api->Notepads[ notepad ] = note;
469}
470
471
472unsigned32 MY_task_get_note(
473  Thread_Control *the_thread,
474  unsigned32      notepad
475)
476{
477  RTEMS_API_Control    *api;
478 
479  api = the_thread->API_Extensions[ THREAD_API_RTEMS ];
480
481  return api->Notepads[ notepad ];
482}
483
484void *MY_CPU_Context_FP_start(
485  void       *base,
486  unsigned32  offset
487)
488{
489  return _CPU_Context_Fp_start( base, offset );
490}
491#endif
Note: See TracBrowser for help on using the repository browser.