source: rtems/cpukit/libcsupport/src/newlibc.c @ 07a3253d

4.104.114.84.95
Last change on this file since 07a3253d was 07a3253d, checked in by Joel Sherrill <joel.sherrill@…>, on 11/23/98 at 19:07:58

Added base version of file system infrastructure. This includes a major
overhaul of the RTEMS system call interface. This base file system is
the "In-Memory File System" aka IMFS.

The design and implementation was done by the following people:

+ Joel Sherrill (joel@…)
+ Jennifer Averett (jennifer@…)
+ Steve "Mr Mount" Salitasc (salitasc@…)
+ Kerwin Wade (wade@…)

PROBLEMS
========

+ It is VERY likely that merging this will break the UNIX port. This

can/will be fixed.

+ There is likely some reentrancy/mutual exclusion needed.

+ Eventually, there should be a "mini-IMFS" description table to

eliminate links, symlinks, etc to save memory. All you need to
have "classic RTEMS" functionality is technically directories
and device IO. All the rest could be left out to save memory.

  • Property mode set to 100644
File size: 9.7 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#endif
397
398/* #if !defined(RTEMS_POSIX_API) || defined(__GO32__) */
399#if !defined(RTEMS_POSIX_API)
400int kill( pid_t pid, int sig )
401{
402  return 0;
403}
404#endif
405
406int __kill( pid_t pid, int sig )
407{
408  return 0;
409}
410
411#if !defined(RTEMS_POSIX_API)
412unsigned int sleep(
413  unsigned int seconds
414)
415{
416  rtems_status_code status;
417  rtems_interval    ticks_per_second;
418  rtems_interval    ticks;
419 
420  status = rtems_clock_get(
421    RTEMS_CLOCK_GET_TICKS_PER_SECOND,
422    &ticks_per_second
423  );
424 
425  ticks = seconds * ticks_per_second;
426 
427  status = rtems_task_wake_after( ticks );
428 
429  /*
430   *  Returns the "unslept" amount of time.  In RTEMS signals are not
431   *  interruptable, so tasks really sleep all of the requested time.
432   */
433 
434  return 0;
435}
436#endif
437
438
439/*
440 *  Newlib Interface Support
441 *
442 *  Routines to Access Internal RTEMS Resources without violating
443 *  kernel visibility.
444 *
445 */
446
447void MY_task_set_note(
448  Thread_Control *the_thread,
449  unsigned32      notepad,
450  unsigned32      note
451)
452{
453  RTEMS_API_Control    *api;
454 
455  api = the_thread->API_Extensions[ THREAD_API_RTEMS ];
456
457  if ( api )
458    api->Notepads[ notepad ] = note;
459}
460
461
462unsigned32 MY_task_get_note(
463  Thread_Control *the_thread,
464  unsigned32      notepad
465)
466{
467  RTEMS_API_Control    *api;
468 
469  api = the_thread->API_Extensions[ THREAD_API_RTEMS ];
470
471  return api->Notepads[ notepad ];
472}
473
474void *MY_CPU_Context_FP_start(
475  void       *base,
476  unsigned32  offset
477)
478{
479  return _CPU_Context_Fp_start( base, offset );
480}
481#endif
Note: See TracBrowser for help on using the repository browser.