thread_get_state.c [plain text]
#include <mach/mach.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <pthread.h>
#include <sys/mman.h>
#include <dispatch/dispatch.h>
#include <sys/sysctl.h>
#include "excserver.h"
void *handler(void *);
void *spin(void *);
dispatch_semaphore_t start_sema;
volatile int iteration;
#define COUNT 10000
int main(int argc, char *argv[]) {
int ret;
pthread_t handle_thread;
char *buffer = valloc(4096);
int i;
int ncpu;
size_t ncpucount = sizeof(ncpu);
start_sema = dispatch_semaphore_create(0);
ret = sysctlbyname("hw.ncpu", &ncpu, &ncpucount, NULL, 0);
if (ret)
err(1, "sysctlbyname");
for (i=0; i < ncpu; i++) {
pthread_t spin_thread;
ret = pthread_create(&spin_thread, NULL, spin, NULL);
if (ret)
err(1, "pthread_create");
}
sleep(1);
ret = pthread_create(&handle_thread, NULL, handler, NULL);
if (ret)
err(1, "pthread_create");
dispatch_semaphore_wait(start_sema, DISPATCH_TIME_FOREVER);
for (iteration = 0; iteration < COUNT; iteration++) {
ret = mprotect(buffer, 4096, PROT_NONE);
if (ret != 0)
err(1, "mprotect");
usleep(1000);
volatile float a = ((float)iteration)/2.4f;
*buffer = '!';
}
return 0;
}
void *handler(void *arg __unused) {
kern_return_t kret;
mach_port_t exception_port;
kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
&exception_port);
if (kret != KERN_SUCCESS)
errx(1, "mach_port_allocate: %s (%d)", mach_error_string(kret), kret);
kret = mach_port_insert_right(mach_task_self(), exception_port, exception_port, MACH_MSG_TYPE_MAKE_SEND);
if (kret != KERN_SUCCESS)
errx(1, "mach_port_insert_right: %s (%d)", mach_error_string(kret), kret);
kret = task_set_exception_ports(mach_task_self(),
EXC_MASK_BAD_ACCESS,
exception_port,
EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
0);
if (kret != KERN_SUCCESS)
errx(1, "task_set_exception_ports: %s (%d)", mach_error_string(kret), kret);
dispatch_semaphore_signal(start_sema);
kret = mach_msg_server(mach_exc_server, MACH_MSG_SIZE_RELIABLE, exception_port, 0);
if (kret != KERN_SUCCESS)
errx(1, "mach_msg_server: %s (%d)", mach_error_string(kret), kret);
return NULL;
}
kern_return_t catch_mach_exception_raise
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
mach_exception_data_t code,
mach_msg_type_number_t codeCnt
)
{
int ret;
kern_return_t kret;
thread_state_flavor_t flavors[128];
thread_state_data_t state;
mach_msg_type_number_t count;
int i, flcount;
count = sizeof(flavors)/sizeof(natural_t);
kret = thread_get_state(thread, THREAD_STATE_FLAVOR_LIST_NEW, (thread_state_t)flavors, &count);
if (kret == KERN_INVALID_ARGUMENT) {
count = sizeof(flavors)/sizeof(natural_t);
kret = thread_get_state(thread, THREAD_STATE_FLAVOR_LIST, (thread_state_t)flavors, &count);
if (kret != KERN_SUCCESS)
errx(1, "thread_get_state(THREAD_STATE_FLAVOR_LIST): %s (%d)", mach_error_string(kret), kret);
} else if (kret != KERN_SUCCESS)
errx(1, "thread_get_state(THREAD_STATE_FLAVOR_LIST_NEW): %s (%d)", mach_error_string(kret), kret);
flcount = count;
for (i=0; i < flcount; i++) {
thread_state_flavor_t flavor;
flavor = flavors[(i + iteration) % flcount];
count = THREAD_STATE_MAX;
kret = thread_get_state(thread, flavor, (thread_state_t)state, &count);
if (kret != KERN_SUCCESS)
errx(1, "thread_get_state(%d): %s (%d)", flavor, mach_error_string(kret), kret);
}
ret = mprotect((void *)code[1], 4096, PROT_WRITE);
if (ret != 0)
err(1, "mprotect");
return KERN_SUCCESS;
}
kern_return_t catch_mach_exception_raise_state
(
mach_port_t exception_port,
exception_type_t exception,
const mach_exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
errx(1, "Unsupported catch_mach_exception_raise_state");
return KERN_NOT_SUPPORTED;
}
kern_return_t catch_mach_exception_raise_state_identity
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
mach_exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
errx(1, "Unsupported catch_mach_exception_raise_state_identity");
return KERN_NOT_SUPPORTED;
}
void *spin(void *arg __unused) {
volatile unsigned int a;
while (1) {
a++;
}
return NULL;
}