void SCHEDULER_add_event(int64_t seq_time, SchedulerCallback callback, const union SuperType *args, int num_args, enum SchedulerPriority priority){ R_ASSERT(PLAYER_current_thread_has_lock()); // An event created by an RT_process function needs to run right away. // If not it won't be run until the next audio block since SCHEDULER_called_per_block // has already been called for this audio block. // (Q: why not do this for events genereated by the editor too? // A: Because then effects could be run after notes, "note on" events could be run before "note off" events, and so forth) if (false==pc->is_treating_editor_events && seq_time < pc->end_time) { callback(seq_time, args); return; } int64_t time = seq_to_scheduler_time(seq_time); //args=NULL; // test crashreporter #if 0 printf("|||||||||| Adding event at seq_time %d, scheduler_time %d. g_current_time: %d, pc->start_time: %d\n", (int)seq_time,(int)time, (int)g_current_time,(int)pc->start_time); #endif if(g_queue_size > QUEUE_SIZE-2){ printf("SCHEDULER: queue full. Skipping.\n"); return; } if(num_args>MAX_ARGS){ printf("Max %d args allowed for scheduler...\n",MAX_ARGS); return; } // Add priority bit. time = time << SCHEDULER_NUM_PRIORITY_BITS; time = time + priority; event_t *event = get_free_event(); event->callback=callback; event->time = time; g_queue_size++; int i = g_queue_size; int new_i = i >> 1; while(time <= g_queue[new_i]->time){ // '<=' (instead of '<') means that the event will be inserted after events with the same time. g_queue[i] = g_queue[new_i]; i = new_i; new_i = new_i >> 1; } g_queue[i] = event; int argnum; for(argnum=0;argnum<num_args;argnum++) event->args[argnum] = args[argnum]; }
/* * monitor_msg - thread routine to monitor messages. */ void * monitor_msg( void *vlibrary) { int exit_status = 0; sigset_t signal_set; library_t *library = (library_t *)vlibrary; robo_event_t *current_event; struct sigaction sig_action; message_request_t *message, shutdown; enum sam_mess_type mtype; /* dummy up a shutdown message */ (void) memset(&shutdown, 0, sizeof (message_request_t)); (void) memset(&sig_action, 0, sizeof (struct sigaction)); shutdown.mtype = MESS_MT_SHUTDOWN; /* LINTED constant truncated by assignment */ shutdown.message.magic = MESSAGE_MAGIC; shutdown.message.command = MESS_CMD_SHUTDOWN; /* * Should have been called with all signals blocked, * now let sigemt be delivered and just exit when it is */ sig_action.sa_handler = sig_catch; sig_action.sa_flags = 0; (void) sigemptyset(&signal_set); (void) sigaddset(&signal_set, SIGEMT); (void) sigaction(SIGEMT, &sig_action, (struct sigaction *)NULL); (void) thr_sigsetmask(SIG_UNBLOCK, &signal_set, NULL); mutex_lock(&library->mutex); /* wait for initialize */ mutex_unlock(&library->mutex); message = (message_request_t *)SHM_REF_ADDR(library->un->dt.rb.message); if (thr_create(NULL, MD_THR_STK, stk_acs_response, (void *)library, (THR_BOUND | THR_NEW_LWP | THR_DETACHED), NULL)) { sam_syslog(LOG_CRIT, "Unable to start stk_acs_response thread: %m."); thr_exit(NULL); } /* Main loop */ for (;;) { current_event = get_free_event(library); /* * Zeroing the struct has the effect of initializing * the mutex and the condition to USYNC_THREAD, just * what we want */ (void) memset(current_event, 0, sizeof (robo_event_t)); current_event->status.bits = REST_FREEMEM; /* Wait for a message */ mutex_lock(&message->mutex); while (message->mtype == MESS_MT_VOID) cond_wait(&message->cond_r, &message->mutex); /* Copy the request into the event */ current_event->request.message = message->message; mtype = message->mtype; /* capture message type */ message->mtype = MESS_MT_VOID; /* release the message area */ message->message.exit_id.pid = 0; cond_signal(&message->cond_i); /* and wake up anyone waiting */ mutex_unlock(&message->mutex); if (mtype == MESS_MT_APIHELP) { current_event->next = NULL; mutex_lock(&stk_acs_mutex); /* * If the list is NULL, this will be the only * entry on the list. Set the head and last to current */ if (stk_acs_event_head == NULL) { stk_acs_event_head = stk_acs_event_last = current_event; cond_signal(&stk_acs_cond); } else { /* * If the head is not null, last points to the * last entry on the list. Point last * next to the current then set last = current */ stk_acs_event_last->next = current_event; stk_acs_event_last = current_event; } mutex_unlock(&stk_acs_mutex); } else { current_event->type = EVENT_TYPE_MESS; /* * Put the event on the list and * wake up the event handler */ add_to_end(library, current_event); if (message->mtype == MESS_MT_SHUTDOWN) { if (DBG_LVL(SAM_DBG_DEBUG)) sam_syslog(LOG_DEBUG, "shutdown request:%s:%d.", __FILE__, __LINE__); threads[STK_MSG_THREAD] = (thread_t)-1; thr_exit(&exit_status); /* NOTREACHED */ return (NULL); } } } }