source: rtems/cpukit/libcsupport/src/newlibc.c @ eb6fafd

4.104.114.84.95
Last change on this file since eb6fafd was eb6fafd, checked in by Joel Sherrill <joel.sherrill@…>, on 01/19/99 at 20:19:22

Per bug report from Jiri Gaisler that RTEMS would no longer build
with the --disable-posix option, stubs for some routines (_getpid_r and
_kill_r) that are normally defined with POSIX were added.

  • 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)
363#if !defined(pc386)
364void _exit(int status)
365{
366    libc_wrapup(); /* Why? XXX */
367    rtems_shutdown_executive(status);
368}
369#endif
370
371#else
372
373void exit(int status)
374{
375    libc_wrapup();
376    rtems_shutdown_executive(status);
377}
378#endif
379
380
381/*
382 *  These are directly supported (and completely correct) in the posix api.
383 */
384
385pid_t __getpid(void)
386{
387  return getpid();
388}
389
390/* #if !defined(RTEMS_POSIX_API) || defined(__GO32__) */
391#if !defined(RTEMS_POSIX_API)
392pid_t getpid(void)
393{
394  return 0;
395}
396
397pid_t _getpid_r(
398  struct _reent *ptr
399)
400{
401  return getpid();
402}
403#endif
404
405/* #if !defined(RTEMS_POSIX_API) || defined(__GO32__) */
406#if !defined(RTEMS_POSIX_API)
407int kill( pid_t pid, int sig )
408{
409  return 0;
410}
411
412int _kill_r( pid_t pid, int sig )
413{
414  return 0;
415}
416#endif
417
418int __kill( pid_t pid, int sig )
419{
420  return 0;
421}
422
423#if !defined(RTEMS_POSIX_API)
424unsigned int sleep(
425  unsigned int seconds
426)
427{
428  rtems_status_code status;
429  rtems_interval    ticks_per_second;
430  rtems_interval    ticks;
431 
432  status = rtems_clock_get(
433    RTEMS_CLOCK_GET_TICKS_PER_SECOND,
434    &ticks_per_second
435  );
436 
437  ticks = seconds * ticks_per_second;
438 
439  status = rtems_task_wake_after( ticks );
440 
441  /*
442   *  Returns the "unslept" amount of time.  In RTEMS signals are not
443   *  interruptable, so tasks really sleep all of the requested time.
444   */
445 
446  return 0;
447}
448#endif
449
450
451/*
452 *  Newlib Interface Support
453 *
454 *  Routines to Access Internal RTEMS Resources without violating
455 *  kernel visibility.
456 *
457 */
458
459void MY_task_set_note(
460  Thread_Control *the_thread,
461  unsigned32      notepad,
462  unsigned32      note
463)
464{
465  RTEMS_API_Control    *api;
466 
467  api = the_thread->API_Extensions[ THREAD_API_RTEMS ];
468
469  if ( api )
470    api->Notepads[ notepad ] = note;
471}
472
473
474unsigned32 MY_task_get_note(
475  Thread_Control *the_thread,
476  unsigned32      notepad
477)
478{
479  RTEMS_API_Control    *api;
480 
481  api = the_thread->API_Extensions[ THREAD_API_RTEMS ];
482
483  return api->Notepads[ notepad ];
484}
485
486void *MY_CPU_Context_FP_start(
487  void       *base,
488  unsigned32  offset
489)
490{
491  return _CPU_Context_Fp_start( base, offset );
492}
493#endif
Note: See TracBrowser for help on using the repository browser.