source: rtems/c/src/exec/libcsupport/src/newlibc.c @ 8dd1276

4.104.114.84.95
Last change on this file since 8dd1276 was 8dd1276, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 5, 1999 at 7:21:34 PM

Removed go32 ifdefs

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