clone() およびその他のカーネル ユーティリティを使用して、Linux ベースのシンプルなマルチスレッド ライブラリを構築しようとしています。元の NPTL コードを調べてみましたが、少し多すぎます。
それが、たとえば create メソッドを想像する方法です。
typedef int sk_thr_id;
typedef void *sk_thr_arg;
typedef int (*sk_thr_func)(sk_thr_arg);
sk_thr_id sk_thr_create(sk_thr_func f, sk_thr_arg a){
void* stack;
stack = malloc( 1024*64 );
if ( stack == 0 ){
perror( "malloc: could not allocate stack" );
exit( 1 );
}
return ( clone(f, (char*) stack + FIBER_STACK, SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM, a ) );
}
1: 正しい clone() フラグがどうあるべきかよくわかりません。これらが単純な例で使用されていることがわかりました。ここでの一般的な指示は大歓迎です。
以下は、futex を使用して作成されたミューテックス プリミティブの一部です (今のところ、自分のコードではありません)。
#define cmpxchg(P, O, N) __sync_val_compare_and_swap((P), (O), (N))
#define cpu_relax() asm volatile("pause\n": : :"memory")
#define barrier() asm volatile("": : :"memory")
static inline unsigned xchg_32(void *ptr, unsigned x)
{
__asm__ __volatile__("xchgl %0,%1"
:"=r" ((unsigned) x)
:"m" (*(volatile unsigned *)ptr), "0" (x)
:"memory");
return x;
}
static inline unsigned short xchg_8(void *ptr, char x)
{
__asm__ __volatile__("xchgb %0,%1"
:"=r" ((char) x)
:"m" (*(volatile char *)ptr), "0" (x)
:"memory");
return x;
}
int sys_futex(void *addr1, int op, int val1, struct timespec *timeout, void *addr2, int val3)
{
return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
}
typedef union mutex mutex;
union mutex
{
unsigned u;
struct
{
unsigned char locked;
unsigned char contended;
} b;
};
int mutex_init(mutex *m, const pthread_mutexattr_t *a)
{
(void) a;
m->u = 0;
return 0;
}
int mutex_lock(mutex *m)
{
int i;
/* Try to grab lock */
for (i = 0; i < 100; i++)
{
if (!xchg_8(&m->b.locked, 1)) return 0;
cpu_relax();
}
/* Have to sleep */
while (xchg_32(&m->u, 257) & 1)
{
sys_futex(m, FUTEX_WAIT_PRIVATE, 257, NULL, NULL, 0);
}
return 0;
}
int mutex_unlock(mutex *m)
{
int i;
/* Locked and not contended */
if ((m->u == 1) && (cmpxchg(&m->u, 1, 0) == 1)) return 0;
/* Unlock */
m->b.locked = 0;
barrier();
/* Spin and hope someone takes the lock */
for (i = 0; i < 200; i++)
{
if (m->b.locked) return 0;
cpu_relax();
}
/* We need to wake someone up */
m->b.contended = 0;
sys_futex(m, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0);
return 0;
}
2: 私にとっての主な質問は、「結合」プリミティブをどのように実装するかです。私はそれがfutexにも基づいているはずであることを知っています。今のところ、何かを思いつくのは苦労しています。
3: スレッドが終了した後に (割り当てられたスタックなど) をクリーンアップする方法が必要です。私もこれを行う良い方法は本当にありません。
おそらくこれらの場合、すべてのスレッドのユーザー空間に追加の構造が必要で、いくつかの情報が保存されている必要があります。誰かがこれらの問題を解決するための良い方向に私を向けることができますか?
4: スレッドが実行されている時間、スレッドが最後にスケジュールされてからの経過時間などを知る方法が必要です。そのような情報を提供するカーネル呼び出しはありますか?
前もって感謝します!