0,0 → 1,293 |
/**************************************************************************** |
* |
* 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 |
; |
*/ |
|
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(); |
} |
|