マルチコンテキスト対応
注釈
これは資料的なドキュメントです。SOLID を使用するだけならば意識する必要はありません。
標準 C ライブラリのマルチコンテキスト対応について解説します。
どの関数に、どのマルチコンテキスト対応が必要なのかは、exeGCC 付属の man/library_overview.xls エクセルファイルを参照してください。
errno のマルチコンテキスト対応
include/errno.h
errno はグローバル変数では無く、関数呼び出しになっています。
int *__get_errno_addr(void);
#ifndef errno
#define errno (*__get_errno_addr())
#endif
source/kwin32.h
マルチコンテキストで VLINK 関数を使用したい場合も、同様に _vlink_errno の再定義が必要です。_vlink_errno は実装詳細なので、ローカルヘッダで errno と同様に定義されています。
int *__get_vlink_errno_addr(void);
/* DOS CALL return Error Code */
#ifndef _vlink_errno
#define _vlink_errno (*__get_vlink_errno_addr())
#endif
source/errno.c
デフォルトの実装です。単にグローバル変数のアドレスを返しているだけなので、マルチコンテキスト非対応です。
#include <errno.h>
#include "kwin32.h"
int __global_errno;
int __global_vlink_errno;
__attribute__ ((weak))
int *__get_errno_addr(void)
{
return &__global_errno;
}
__attribute__ ((weak))
int *__get_vlink_errno_addr(void)
{
return &__global_vlink_errno;
}
これらの関数を再定義し、コンテキストごとに独立したメモリのアドレスを返すようにすれば、コンテキスト切り替えにより errno が上書きされてしまう事態を防ぐことができます。この関数は weak symbol として定義されているので、どこでも構いませんので通常の関数定義(strong symbol になります)を行えば、多重定義エラーにはならず、優先してリンクされます。
malloc 系関数のマルチコンテキスト対応
malloc 系関数には、独自の排他制御用スタブが提供されています。
include/_malloc.h
malloc/calloc/realloc/free 関数の入り口と出口で、それぞれ _malloc_start_fnc と _malloc_end_fnc の関数ポインタが、非ゼロの場合、呼び出されます。
extern void (*_malloc_start_fnc)(void);
extern void (*_malloc_end_fnc)(void);
source/ind_etc.c が、μITRON のミューテックスを使用した場合のサンプルコードとなっています。(ユーザーズマニュアルにも解説があります。)
VLINK のマルチコンテキスト対応
VLINK 関数にも malloc 系関数と同様の排他制御用スタブが存在します。
include/_malloc.h
malloc 系関数のスタブと同様に、VLINK 関数の入り口と出口で、関数ポインタが非ゼロの場合に呼び出されます。
extern void (*_vlink_start_fnc)(void);
extern void (*_vlink_end_fnc)(void);
また、同様に source/ind_etc.c が、μITRON のミューテックスを使用した場合のサンプルコードとなっています。