From ac7d5ef06a6d6e8d84abbd1f0b82162725f98326 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 11 May 1995 17:39:37 +0000 Subject: Initial revision --- c/src/exec/libcsupport/src/newlibc.c | 292 +++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 c/src/exec/libcsupport/src/newlibc.c (limited to 'c/src/exec/libcsupport/src/newlibc.c') diff --git a/c/src/exec/libcsupport/src/newlibc.c b/c/src/exec/libcsupport/src/newlibc.c new file mode 100644 index 0000000000..3c5e58b67c --- /dev/null +++ b/c/src/exec/libcsupport/src/newlibc.c @@ -0,0 +1,292 @@ +/* + * @(#)newlibc.c 1.8 - 95/04/25 + * + */ + +#if defined(RTEMS_NEWLIB) + +/* + * File: $RCSfile$ + * Project: PixelFlow + * Created: 94/12/7 + * Revision: $Revision$ + * Last Mod: $Date$ + * + * COPYRIGHT (c) 1994 by Division Incorporated + * + * To anyone who acknowledges that this file is provided "AS IS" + * without any express or implied warranty: + * permission to use, copy, modify, and distribute this file + * for any purpose is hereby granted without fee, provided that + * the above copyright notice and this notice appears in all + * copies, and that the name of Division Incorporated not be + * used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * Division Incorporated makes no representations about the + * suitability of this software for any purpose. + * + * Description: + * Implementation of hooks for the CYGNUS newlib libc + * These hooks set things up so that: + * '_REENT' is switched at task switch time. + * + * + * TODO: + * + * NOTE: + * + * $Id$ + * + */ + +#include +#include +#include /* for free() */ +#include /* for memset() */ + +#include /* for extern of _REENT (aka _impure_ptr) */ + +#include "internal.h" + +#define LIBC_NOTEPAD RTEMS_NOTEPAD_LAST + + +int libc_reentrant; /* do we think we are reentrant? */ +struct _reent libc_global_reent = _REENT_INIT(libc_global_reent);; + +/* + * CYGNUS newlib routine that does atexit() processing and flushes + * stdio streams + * undocumented + */ + +extern void _wrapup_reent(struct _reent *); +extern void _reclaim_reent(struct _reent *); + +void +libc_wrapup(void) +{ + _wrapup_reent(0); + if (_REENT != &libc_global_reent) + { + _wrapup_reent(&libc_global_reent); +#if 0 + /* don't reclaim this one, just in case we do printfs */ + /* on our way out to ROM */ + _reclaim_reent(&libc_global_reent); +#endif + _REENT = &libc_global_reent; + } +} + + +rtems_extension +libc_create_hook(rtems_tcb *current_task, + rtems_tcb *creating_task) +{ + MY_task_set_note(creating_task, LIBC_NOTEPAD, 0); +} + +/* + * Called for all user TASKS (system tasks are SYSI and IDLE) + */ + +rtems_extension +libc_start_hook(rtems_tcb *current_task, + rtems_tcb *starting_task) +{ + struct _reent *ptr; + + /* NOTE: our malloc is reentrant without a reent ptr since + * it is based on region manager + */ + + ptr = (struct _reent *) malloc(sizeof(struct _reent)); + + /* GCC extension: structure constants */ + *ptr = (struct _reent) _REENT_INIT((*ptr)); + + MY_task_set_note(starting_task, LIBC_NOTEPAD, (rtems_unsigned32) ptr); +} + +rtems_extension +libc_switch_hook(rtems_tcb *current_task, + rtems_tcb *heir_task) +{ + rtems_unsigned32 impure_value; + + /* XXX We can't use rtems_task_set_note() here since SYSI task has a + * tid of 0, which is treated specially (optimized, actually) + * by rtems_task_set_note + */ + + impure_value = (rtems_unsigned32) _REENT; + MY_task_set_note(current_task, LIBC_NOTEPAD, impure_value); + + _REENT = (struct _reent *) MY_task_get_note(heir_task, LIBC_NOTEPAD); + +} + +/* + * Function: libc_delete_hook + * Created: 94/12/10 + * + * Description: + * Called when a task is deleted. + * Must restore the new lib reentrancy state for the new current + * task. + * + * Parameters: + * + * + * Returns: + * + * + * Side Effects: + * + * Notes: + * + * + * Deficiencies/ToDo: + * + * + */ +rtems_extension +libc_delete_hook(rtems_tcb *current_task, + rtems_tcb *deleted_task) +{ + struct _reent *ptr; + + /* + * The reentrancy structure was allocated by newlib using malloc() + */ + + if (current_task == deleted_task) + { + ptr = _REENT; + } + else + { + ptr = (struct _reent *) MY_task_get_note(deleted_task, LIBC_NOTEPAD); + } + + if (ptr) + { + _wrapup_reent(ptr); + _reclaim_reent(ptr); + } + + MY_task_set_note(deleted_task, LIBC_NOTEPAD, 0); + + /* + * Require the switch back to another task to install its own + */ + + if (current_task == deleted_task) + { + _REENT = 0; + } +} + +/* + * Function: libc_init + * Created: 94/12/10 + * + * Description: + * Init libc for CYGNUS newlib + * Set up _REENT to use our global libc_global_reent. + * (newlib provides a global of its own, but we prefer our + * own name for it) + * + * If reentrancy is desired (which it should be), then + * we install the task extension hooks to maintain the + * newlib reentrancy global variable _REENT on task + * create, delete, switch, exit, etc. + * + * Parameters: + * reentrant non-zero if reentrant library desired. + * + * Returns: + * + * Side Effects: + * installs libc extensions if reentrant. + * + * Notes: + * + * + * Deficiencies/ToDo: + * + */ + +void +libc_init(int reentrant) +{ + rtems_extensions_table libc_extension; + rtems_id extension_id; + rtems_status_code rc; + + _REENT = &libc_global_reent; + + if (reentrant) + { + memset(&libc_extension, 0, sizeof(libc_extension)); + + libc_extension.rtems_task_create = libc_create_hook; + libc_extension.rtems_task_start = libc_start_hook; + libc_extension.task_switch = libc_switch_hook; + libc_extension.rtems_task_delete = libc_delete_hook; + + rc = rtems_extension_create(rtems_build_name('L', 'I', 'B', 'C'), + &libc_extension, &extension_id); + if (rc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(rc); + + libc_reentrant = reentrant; + } +} + + +void +exit(int status) +{ + libc_wrapup(); + rtems_shutdown_executive(status); +} + + +/* + * Function: _exit + * Created: 94/12/10 + * + * Description: + * Called from exit() after it does atexit() processing and stdio fflush's + * + * called from bottom of exit() to really delete the task. + * If we are using reentrant libc, then let the delete extension + * do all the work, otherwise if a shutdown is in progress, + * then just do it. + * + * Parameters: + * exit status + * + * Returns: + * does not return + * + * Side Effects: + * + * Notes: + * + * + * Deficiencies/ToDo: + * + * + */ + +#ifndef RTEMS_UNIX +void _exit(int status) +{ + rtems_shutdown_executive(status); +} +#endif + +#endif -- cgit v1.2.3