+#pragma mark **** ast ****
+static chudxnu_perfmon_ast_callback_func_t perfmon_ast_callback_fn = NULL;
+
+static kern_return_t chudxnu_private_chud_ast_callback(int trapno, struct savearea *ssp, unsigned int dsisr, unsigned int dar)
+{
+ boolean_t oldlevel = ml_set_interrupts_enabled(FALSE);
+ ast_t *myast = ast_pending();
+ kern_return_t retval = KERN_FAILURE;
+
+ if(*myast & AST_PPC_CHUD_URGENT) {
+ *myast &= ~(AST_PPC_CHUD_URGENT | AST_PPC_CHUD);
+ if((*myast & AST_PREEMPTION) != AST_PREEMPTION) *myast &= ~(AST_URGENT);
+ retval = KERN_SUCCESS;
+ } else if(*myast & AST_PPC_CHUD) {
+ *myast &= ~(AST_PPC_CHUD);
+ retval = KERN_SUCCESS;
+ }
+
+ if(perfmon_ast_callback_fn) {
+ struct ppc_thread_state64 state;
+ mach_msg_type_number_t count;
+ count = PPC_THREAD_STATE64_COUNT;
+
+ if(chudxnu_thread_get_state(current_thread(), PPC_THREAD_STATE64, (thread_state_t)&state, &count, FALSE)==KERN_SUCCESS) {
+ (perfmon_ast_callback_fn)(PPC_THREAD_STATE64, (thread_state_t)&state, count);
+ }
+ }
+
+#if 0
+ // ASTs from ihandler go through thandler and are made to look like traps
+ // always handle AST_PPC_CHUD_URGENT if there's a callback
+ // only handle AST_PPC_CHUD if it's the only AST pending
+ if(perfmon_ast_callback_fn && ((*myast & AST_PPC_CHUD_URGENT) || ((*myast & AST_PPC_CHUD) && !(*myast & AST_URGENT)))) {
+ struct ppc_thread_state64 state;
+ mach_msg_type_number_t count = PPC_THREAD_STATE64_COUNT;
+ chudxnu_copy_savearea_to_threadstate(PPC_THREAD_STATE64, (thread_state_t)&state, &count, ssp);
+ if(*myast & AST_PPC_CHUD_URGENT) {
+ *myast &= ~(AST_PPC_CHUD_URGENT | AST_PPC_CHUD);
+ if((*myast & AST_PREEMPTION) != AST_PREEMPTION) *myast &= ~(AST_URGENT);
+ retval = KERN_SUCCESS;
+ } else if(*myast & AST_PPC_CHUD) {
+ *myast &= ~(AST_PPC_CHUD);
+ retval = KERN_SUCCESS;
+ }
+ (perfmon_ast_callback_fn)(PPC_THREAD_STATE64, (thread_state_t)&state, count);
+ }
+#endif
+
+ ml_set_interrupts_enabled(oldlevel);
+ return retval;
+}
+