forked from KolibriOS/kolibrios
616f769298
git-svn-id: svn://kolibrios.org@702 a494cfbc-eb01-0410-851d-a64ba20cac60
294 lines
9.0 KiB
C
294 lines
9.0 KiB
C
/****************************************************************************
|
|
*
|
|
* Open Watcom Project
|
|
*
|
|
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* This file contains Original Code and/or Modifications of Original
|
|
* Code as defined in and that are subject to the Sybase Open Watcom
|
|
* Public License version 1.0 (the 'License'). You may not use this file
|
|
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
|
|
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
|
|
* provided with the Original Code and Modifications, and is also
|
|
* available at www.sybase.com/developer/opensource.
|
|
*
|
|
* The Original Code and all software distributed under the License are
|
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
|
|
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
|
|
* NON-INFRINGEMENT. Please see the License for the specific language
|
|
* governing rights and limitations under the License.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Description: Initialization and termination of clib.
|
|
*
|
|
****************************************************************************/
|
|
|
|
|
|
#include "variety.h"
|
|
#include "initfini.h"
|
|
#include "rtinit.h"
|
|
|
|
#define PNEAR ((__type_rtp)0)
|
|
#define PFAR ((__type_rtp)1)
|
|
#define PDONE ((__type_rtp)2)
|
|
|
|
#if ( COMP_CFG_COFF == 1 ) || defined(__AXP__) || defined(__PPC__) || defined(__MIPS__)
|
|
// following is an attempt to drop the need for an assembler
|
|
// segment definitions file
|
|
// unfortunately, the use of XIB,XIE,YIB,YIE doesn't get the
|
|
// right sort of segments by default
|
|
#pragma data_seg( ".rtl$xib", "DATA" );
|
|
YIXI( TS_SEG_XIB, _Start_XI, 0, 0 )
|
|
#pragma data_seg( ".rtl$xie", "DATA" );
|
|
YIXI( TS_SEG_XIE, _End_XI, 0, 0 )
|
|
#pragma data_seg( ".rtl$yib", "DATA" );
|
|
YIXI( TS_SEG_YIB, _Start_YI, 0, 0 )
|
|
#pragma data_seg( ".rtl$yie", "DATA" );
|
|
YIXI( TS_SEG_YIE, _End_YI, 0, 0 )
|
|
#pragma data_seg( ".data", "DATA" );
|
|
#elif defined(_M_IX86)
|
|
extern struct rt_init _Start_XI;
|
|
extern struct rt_init _End_XI;
|
|
|
|
extern struct rt_init _Start_YI;
|
|
extern struct rt_init _End_YI;
|
|
#else
|
|
#error unsupported platform
|
|
#endif
|
|
|
|
typedef void (*pfn)(void);
|
|
typedef void (_WCI86FAR * _WCI86FAR fpfn)(void);
|
|
typedef void (_WCI86NEAR * _WCI86NEAR npfn)(void);
|
|
|
|
#if defined(__AXP__) || defined(__PPC__) || defined(__MIPS__)
|
|
#define __GETDS()
|
|
#define save_ds()
|
|
#define restore_ds()
|
|
#define save_es()
|
|
#define restore_es()
|
|
#define setup_es()
|
|
#elif defined(__WINDOWS_386__)
|
|
#define __GETDS()
|
|
#define save_ds()
|
|
#define restore_ds()
|
|
#define save_es()
|
|
#define restore_es()
|
|
#define setup_es()
|
|
#elif defined(__386__)
|
|
#define __GETDS()
|
|
#define save_ds()
|
|
#define restore_ds()
|
|
#if defined(__FLAT__)
|
|
#define save_es()
|
|
#define restore_es()
|
|
#define setup_es()
|
|
#else
|
|
extern void save_es( void );
|
|
#pragma aux save_es = modify exact [es];
|
|
extern void restore_es( void );
|
|
#pragma aux restore_es = modify exact [es];
|
|
extern void setup_es( void );
|
|
#pragma aux setup_es = \
|
|
"push ds" \
|
|
"pop es" \
|
|
modify exact [es];
|
|
#endif
|
|
#elif defined(M_I86)
|
|
extern void save_dx( void );
|
|
#pragma aux save_dx = modify exact [dx];
|
|
extern void _WCI86NEAR __GETDS( void );
|
|
#pragma aux __GETDS "__GETDS";
|
|
extern void save_ds( void );
|
|
#pragma aux save_ds = "push ds" modify exact [sp];
|
|
extern void restore_ds( void );
|
|
#pragma aux restore_ds = "pop ds" modify exact [sp];
|
|
#define save_es()
|
|
#define restore_es()
|
|
#else
|
|
#error unsupported platform
|
|
#endif
|
|
|
|
#if defined(M_I86)
|
|
static void callit_near( npfn *f ) {
|
|
// don't call a null pointer
|
|
if( *f ) {
|
|
save_dx();
|
|
save_ds();
|
|
// call function
|
|
(void)(**f)();
|
|
restore_ds();
|
|
}
|
|
}
|
|
|
|
static void callit_far( fpfn _WCI86NEAR *f ) {
|
|
// don't call a null pointer
|
|
if( *f ) {
|
|
save_ds();
|
|
// call function
|
|
(void)(**f)();
|
|
restore_ds();
|
|
}
|
|
}
|
|
#else
|
|
static void callit( pfn *f ) {
|
|
// don't call a null pointer
|
|
if( *f ) {
|
|
// QNX needs es==ds
|
|
setup_es();
|
|
// call function
|
|
(void)(**f)();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
; - takes priority limit parm in eax, code will run init routines whose
|
|
; priority is < eax (really al [0-255])
|
|
; eax==255 -> run all init routines
|
|
; eax==15 -> run init routines whose priority is <= 15
|
|
;
|
|
*/
|
|
#if defined(M_I86)
|
|
void _WCI86FAR __FInitRtns( unsigned limit ) {
|
|
__InitRtns( limit );
|
|
}
|
|
#endif
|
|
void __InitRtns( unsigned limit ) {
|
|
__type_rtp local_limit;
|
|
struct rt_init _WCI86NEAR *pnext;
|
|
save_ds();
|
|
save_es();
|
|
__GETDS();
|
|
|
|
local_limit = (__type_rtp)limit;
|
|
for(;;) {
|
|
{
|
|
__type_rtp working_limit;
|
|
struct rt_init _WCI86NEAR *pcur;
|
|
|
|
pcur = (struct rt_init _WCI86NEAR*)&_Start_XI;
|
|
#if defined(COMP_CFG_COFF)
|
|
pcur++;
|
|
#endif
|
|
pnext = (struct rt_init _WCI86NEAR*)&_End_XI;
|
|
working_limit = local_limit;
|
|
|
|
// walk list of routines
|
|
while( pcur < (struct rt_init _WCI86NEAR*)&_End_XI ) {
|
|
// if this one hasn't been called
|
|
if( pcur->rtn_type != PDONE ) {
|
|
// if the priority is better than best so far
|
|
if( pcur->priority <= working_limit ) {
|
|
// remember this one
|
|
pnext = pcur;
|
|
working_limit = pcur->priority;
|
|
}
|
|
}
|
|
// advance to next entry
|
|
pcur++;
|
|
}
|
|
// check to see if all done, if we didn't find any
|
|
// candidates then we can return
|
|
if( pnext == (struct rt_init _WCI86NEAR*)&_End_XI ) {
|
|
break;
|
|
}
|
|
}
|
|
#if defined(M_I86)
|
|
if( pnext->rtn_type == PNEAR ) {
|
|
callit_near( (npfn *)&pnext->rtn );
|
|
} else {
|
|
callit_far( (fpfn _WCI86NEAR *)&pnext->rtn );
|
|
}
|
|
#else
|
|
callit( &pnext->rtn );
|
|
#endif
|
|
// mark entry as invoked
|
|
pnext->rtn_type = PDONE;
|
|
}
|
|
restore_es();
|
|
restore_ds();
|
|
}
|
|
|
|
/*
|
|
; - takes priority range parms in eax, edx, code will run fini routines whose
|
|
; priority is >= eax (really al [0-255]) and <= edx (really dl [0-255])
|
|
; eax==0, edx=255 -> run all fini routines
|
|
; eax==16, edx=255 -> run fini routines in range 16..255
|
|
; eax==16, edx=40 -> run fini routines in range 16..40
|
|
*/
|
|
#if defined(M_I86)
|
|
void _WCI86FAR __FFiniRtns( unsigned min_limit, unsigned max_limit ) {
|
|
__FiniRtns( min_limit, max_limit );
|
|
}
|
|
#endif
|
|
void __FiniRtns( unsigned min_limit, unsigned max_limit ) {
|
|
__type_rtp local_min_limit;
|
|
__type_rtp local_max_limit;
|
|
struct rt_init _WCI86NEAR *pnext;
|
|
save_ds();
|
|
save_es();
|
|
__GETDS();
|
|
|
|
local_min_limit = (__type_rtp)min_limit;
|
|
local_max_limit = (__type_rtp)max_limit;
|
|
for(;;) {
|
|
{
|
|
__type_rtp working_limit;
|
|
struct rt_init _WCI86NEAR *pcur;
|
|
|
|
pcur = (struct rt_init _WCI86NEAR*)&_Start_YI;
|
|
#if defined(COMP_CFG_COFF)
|
|
pcur++;
|
|
#endif
|
|
pnext = (struct rt_init _WCI86NEAR*)&_End_YI;
|
|
working_limit = local_min_limit;
|
|
|
|
// walk list of routines
|
|
while( pcur < (struct rt_init _WCI86NEAR*)&_End_YI )
|
|
{
|
|
// if this one hasn't been called
|
|
if( pcur->rtn_type != PDONE ) {
|
|
// if the priority is better than best so far
|
|
if( pcur->priority >= working_limit )
|
|
{
|
|
// remember this one
|
|
pnext = pcur;
|
|
working_limit = pcur->priority;
|
|
}
|
|
}
|
|
// advance to next entry
|
|
pcur++;
|
|
}
|
|
// check to see if all done, if we didn't find any
|
|
// candidates then we can return
|
|
if( pnext == (struct rt_init _WCI86NEAR*)&_End_YI ) {
|
|
break;
|
|
}
|
|
}
|
|
if( pnext->priority <= local_max_limit ) {
|
|
#if defined(M_I86)
|
|
if( pnext->rtn_type == PNEAR ) {
|
|
callit_near( (npfn *)&pnext->rtn );
|
|
} else {
|
|
callit_far( (fpfn _WCI86NEAR *)&pnext->rtn );
|
|
}
|
|
#else
|
|
callit( &pnext->rtn );
|
|
#endif
|
|
}
|
|
// mark entry as invoked even if we don't call it
|
|
// if we didn't call it, it is because we don't want to
|
|
// call finirtns with priority > max_limit, in that case
|
|
// marking the function as called, won't hurt anything
|
|
pnext->rtn_type = PDONE;
|
|
}
|
|
restore_es();
|
|
restore_ds();
|
|
}
|
|
|