LibC: Fix pthread cancellation
Install SIGCANCEL handler for all threads. Remove unneeded atomic stores and loads. States are only changed within the thread itself. Define pthread_testcancel as a macro so it gets inlined inside cancellation points
This commit is contained in:
@@ -49,7 +49,7 @@ struct uthread
|
|||||||
int errno_;
|
int errno_;
|
||||||
int cancel_type;
|
int cancel_type;
|
||||||
int cancel_state;
|
int cancel_state;
|
||||||
int canceled;
|
volatile int canceled;
|
||||||
// FIXME: make this dynamic
|
// FIXME: make this dynamic
|
||||||
uintptr_t dtv[1 + 256];
|
uintptr_t dtv[1 + 256];
|
||||||
};
|
};
|
||||||
@@ -219,6 +219,14 @@ void pthread_testcancel(void);
|
|||||||
void pthread_cleanup_pop(int execute);
|
void pthread_cleanup_pop(int execute);
|
||||||
void pthread_cleanup_push(void (*routine)(void*), void* arg);
|
void pthread_cleanup_push(void (*routine)(void*), void* arg);
|
||||||
|
|
||||||
|
#define _pthread_testcancel() do { \
|
||||||
|
struct uthread* uthread = _get_uthread(); \
|
||||||
|
if (__builtin_expect(uthread->cancel_state == PTHREAD_CANCEL_ENABLE, 1)) \
|
||||||
|
if (__builtin_expect(uthread->canceled, 0)) \
|
||||||
|
pthread_exit(PTHREAD_CANCELED); \
|
||||||
|
} while (0)
|
||||||
|
#define pthread_testcancel() _pthread_testcancel()
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,6 +22,22 @@ struct pthread_trampoline_info_t
|
|||||||
void* arg;
|
void* arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void _pthread_cancel_handler(int)
|
||||||
|
{
|
||||||
|
uthread* uthread = _get_uthread();
|
||||||
|
uthread->canceled = true;
|
||||||
|
if (uthread->cancel_state == PTHREAD_CANCEL_DISABLE)
|
||||||
|
return;
|
||||||
|
if (uthread->cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS)
|
||||||
|
pthread_exit(PTHREAD_CANCELED);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((constructor))
|
||||||
|
static void _install_main_thread_cancel_handler()
|
||||||
|
{
|
||||||
|
signal(SIGCANCEL, &_pthread_cancel_handler);
|
||||||
|
}
|
||||||
|
|
||||||
// stack is 16 byte aligned on entry, this `call` is used to align it
|
// stack is 16 byte aligned on entry, this `call` is used to align it
|
||||||
extern "C" void _pthread_trampoline(void*);
|
extern "C" void _pthread_trampoline(void*);
|
||||||
asm(
|
asm(
|
||||||
@@ -54,6 +70,7 @@ extern "C" void _pthread_trampoline_cpp(void* arg)
|
|||||||
#error
|
#error
|
||||||
#endif
|
#endif
|
||||||
free(arg);
|
free(arg);
|
||||||
|
signal(SIGCANCEL, &_pthread_cancel_handler);
|
||||||
pthread_exit(info.start_routine(info.arg));
|
pthread_exit(info.start_routine(info.arg));
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
@@ -610,25 +627,8 @@ int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(voi
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pthread_cancel_handler(int)
|
|
||||||
{
|
|
||||||
uthread* uthread = _get_uthread();
|
|
||||||
BAN::atomic_store(uthread->canceled, true);
|
|
||||||
if (BAN::atomic_load(uthread->cancel_state) != PTHREAD_CANCEL_ENABLE)
|
|
||||||
return;
|
|
||||||
switch (BAN::atomic_load(uthread->cancel_type))
|
|
||||||
{
|
|
||||||
case PTHREAD_CANCEL_ASYNCHRONOUS:
|
|
||||||
pthread_exit(PTHREAD_CANCELED);
|
|
||||||
case PTHREAD_CANCEL_DEFERRED:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
int pthread_cancel(pthread_t thread)
|
int pthread_cancel(pthread_t thread)
|
||||||
{
|
{
|
||||||
signal(SIGCANCEL, &pthread_cancel_handler);
|
|
||||||
return pthread_kill(thread, SIGCANCEL);
|
return pthread_kill(thread, SIGCANCEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -666,14 +666,10 @@ int pthread_setcanceltype(int type, int* oldtype)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef pthread_testcancel
|
||||||
void pthread_testcancel(void)
|
void pthread_testcancel(void)
|
||||||
{
|
{
|
||||||
uthread* uthread = _get_uthread();
|
_pthread_testcancel();
|
||||||
if (BAN::atomic_load(uthread->cancel_state) != PTHREAD_CANCEL_ENABLE)
|
|
||||||
return;
|
|
||||||
if (!BAN::atomic_load(uthread->canceled))
|
|
||||||
return;
|
|
||||||
pthread_exit(PTHREAD_CANCELED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pthread_getschedparam(pthread_t thread, int* __restrict policy, struct sched_param* __restrict param)
|
int pthread_getschedparam(pthread_t thread, int* __restrict policy, struct sched_param* __restrict param)
|
||||||
|
|||||||
Reference in New Issue
Block a user