マルチコンテキスト対応

注釈

これは資料的なドキュメントです。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 のミューテックスを使用した場合のサンプルコードとなっています。(ユーザーズマニュアルにも解説があります。)