static void uninit(struct ao *ao) { MP_DBG(ao, "Uninit wasapi\n"); struct wasapi_state *state = ao->priv; wasapi_release_proxies(state); if (state->hWake) set_thread_state(ao, WASAPI_THREAD_SHUTDOWN); // wait up to 10 seconds if (state->hAudioThread && WaitForSingleObject(state->hAudioThread, 10000) == WAIT_TIMEOUT) { MP_ERR(ao, "Audio loop thread refuses to abort\n"); return; } SAFE_RELEASE(state->hInitDone, CloseHandle(state->hInitDone)); SAFE_RELEASE(state->hWake, CloseHandle(state->hWake)); SAFE_RELEASE(state->hAudioThread,CloseHandle(state->hAudioThread)); wasapi_change_uninit(ao); talloc_free(state->deviceID); CoUninitialize(); MP_DBG(ao, "Uninit wasapi done\n"); }
int signal_local_semaphore( struct thread* tr, int sem_id ) { struct sem_link *sl; struct thread *target; struct process *proc; proc = tr->process; acquire_spinlock( & (proc->sems_lock) ); if ( proc->sems[ sem_id ].sem_id != sem_id ) { release_spinlock( & (proc->sems_lock) ); return -1; } proc->sems[ sem_id ].count -= 1; // wake up any waiting threads sl = proc->sems[ sem_id ].waiting_list; if ( sl != NULL ) { target = find_thread_with_id( tr->process, sl->tid ); if ( target != NULL ) set_thread_state( target, THREAD_RUNNING ); proc->sems[ sem_id ].waiting_list = sl->next; free( sl ); } release_spinlock( & ( proc->sems_lock ) ); return 0; }
/** * online_first_dead_cpu * @brief Find the first cpu with attributes online and physical_id both * set to 0 and online it. * * @param nthreads * @returns 0 on success, !0 otherwise */ int online_first_dead_cpu(int nthreads, struct dr_info *dr_info) { struct thread *thread; int rc = 1; for (thread = dr_info->all_threads; thread; thread = thread->next) { if (OFFLINE == get_thread_state(thread) && ((thread->phys_id == 0xffffffff) || (thread->phys_id == 0))) { /* just assume that there will be nthreads to online. */ while (nthreads--) { set_thread_state(thread, ONLINE); thread = thread->next; } rc = 0; break; } } if (rc) say(ERROR, "Could not find any threads to online\n"); return rc; }
/** * online cpu * * @param cpu * @param dr_info * @returns 0 on success, !0 otherwise */ int online_cpu(struct dr_node *cpu, struct dr_info *dr_info) { int rc = 0; struct thread *thread = NULL; int found = 0; say(DEBUG, "Onlining cpu %s (%d threads)\n", cpu->name, cpu->cpu_nthreads); /* Hack to work around kernel brain damage (LTC 7692) */ for (thread = dr_info->all_threads; thread; thread = thread->next) { if (thread->cpu == cpu) { found = 1; break; } } if (!found) { /* There are no threads which match this cpu because * the physical_id attribute is not updated until the * cpu is onlined -- this case is for cpus which are * not present at boot but are added afterwards. */ return online_first_dead_cpu(cpu->cpu_nthreads, dr_info); } for (thread = cpu->cpu_threads; thread; thread = thread->sibling) { if (get_thread_state(thread) != ONLINE) rc |= set_thread_state(thread, ONLINE); } return rc; }
int pause( struct thread *tr, uint64_t milliseconds ) { int pos, i, id; struct scheduler_info *si; uint64_t now; uint64_t target; assert( tr != NULL ); // Real thread. assert( milliseconds > 0 ); // Real time assert( tr->cpu == CPUID ); // Current CPU id = tr->cpu; si = &( cpu[ id ].sched ); sched_lock( id, 0 ); now = cpu[ id ].st_systemTime.usage; target = milliseconds + now; // PAUSE INSERTION ...................... if ( si->pause_count == si->pause_size ) { sched_unlock( id ); return -1; } // Add it by finding the position in the queue. for ( pos = 0; pos < si->pause_count; pos++ ) { if ( si->pause_queue[ pos ].request > target ) break; } // Move everything up one. for ( i = si->pause_count; i > pos; i-- ) { si->pause_queue[ i ] = si->pause_queue[ i - 1 ]; } // Insert the pause si->pause_queue[ pos ].tr = tr; si->pause_queue[ pos ].state = tr->state; si->pause_queue[ pos ].request = target; si->pause_queue[ pos ].start = now; si->pause_count += 1; set_thread_state( tr, THREAD_DORMANT ); tr->duration = milliseconds; sched_unlock( id ); return 0; }
/////////////////////////////////////////////////////////////////////////// /// \brief Set the thread state of the \a thread referenced by the /// thread_id \a id. /// /// Set a timer to set the state of the given \a thread to the given /// new value after it expired (after the given duration) /// /// \param id [in] The thread id of the thread the state should /// be modified for. /// \param after_duration /// \param state [in] The new state to be set for the thread /// referenced by the \a id parameter. /// \param state_ex [in] The new extended state to be set for the /// thread referenced by the \a id parameter. /// \param priority /// \param ec [in,out] this represents the error status on exit, /// if this is pre-initialized to \a hpx#throws /// the function will throw on error instead. /// /// \returns /// /// \note As long as \a ec is not pre-initialized to /// \a hpx#throws this function doesn't /// throw but returns the result code using the /// parameter \a ec. Otherwise it throws an instance /// of hpx#exception. inline thread_id_type set_thread_state(thread_id_type const& id, util::steady_duration const& rel_time, thread_state_enum state = pending, thread_state_ex_enum stateex = wait_timeout, thread_priority priority = thread_priority_normal, error_code& ec = throws) { return set_thread_state(id, rel_time.from_now(), state, stateex, priority, ec); }
void random_thread_deallocate( void ) { if( !get_thread_state() ) return; mutex_lock( _random_mutex ); array_push( _random_available_state, get_thread_state() ); mutex_unlock( _random_mutex ); set_thread_state( 0 ); }
/** * cpu_diable_smt * @brief Disable all but one of a cpu's threads * * @param cpu cpu to disable smt on * @returns 0 on success, !0 otherwise */ int cpu_disable_smt(struct dr_node *cpu) { int rc = 0; struct thread *t; int survivor_found = 0; /* Ensure that the first thread of the processor is the thread that is left online * when disabling SMT. */ t = cpu->cpu_threads; if (get_thread_state(t) == OFFLINE) rc |= set_thread_state(t, ONLINE); for (t = cpu->cpu_threads; t != NULL; t = t->sibling) { if (ONLINE == get_thread_state(t)) { if (survivor_found) rc |= set_thread_state(t, OFFLINE); survivor_found = 1; } } return rc; }
/** * offline_cpu * @brief Mark the specified cpu as offline * * @param cpu * @param dr_info * @returns 0 on success, !0 otherwise */ int offline_cpu(struct dr_node *cpu) { int rc = 0; struct thread *thread; say(DEBUG, "Offlining cpu %s (%d threads)\n", cpu->name, cpu->cpu_nthreads); for (thread = cpu->cpu_threads; thread; thread = thread->sibling) { if (get_thread_state(thread) != OFFLINE) rc |= set_thread_state(thread, OFFLINE); } return rc; }
int clean_general( struct process *owner, struct wait_info *wait, int rc ) { struct process *proc; struct thread *tr; int count = 0; int clean = 0; struct wait_info *tmp = wait; struct wait_info *old = NULL; while ( tmp != NULL ) { tmp->success = 0; tmp->rc = rc; clean = 0; // Make sure that it's not already locked. if ( owner->pid == tmp->pid ) proc = owner; else proc = checkout_process( tmp->pid, WRITER ); if ( proc != NULL ) { tr = find_thread_with_id( proc, tmp->tid ); if ( tr != NULL ) { set_thread_state( tr, THREAD_RUNNING ); } else clean = 1; // Nothing waiting on this wait. Need to clean it. if ( proc != owner ) commit_process( proc ); } else clean = 1; // Nothing waiting on this wait. Need to clean it. old = tmp; tmp = tmp->next; // Clean the wait if the waiter was not found. if ( clean == 1 ) free( old ); } return count; }
int destroy_global_semaphore( int pid, int sem_id ) { struct sem_link *sl = NULL; struct sem_link *tmp = NULL; struct process *proc = NULL; struct thread *tr = NULL; if ( sem_id < 0 ) return -1; if ( sem_id >= GLOBAL_SEM_COUNT ) return -1; acquire_spinlock( & global_sems_lock ); if ( ( global_sems[ sem_id ].sem_id != sem_id ) || ( global_sems[ sem_id ].pid != pid ) ) { // Invalid or not allowed. release_spinlock( & global_sems_lock ); return -1; } // Tell the waiting guys to go away. sl = global_sems[ sem_id ].waiting_list; while ( sl != NULL ) { tmp = sl; proc = checkout_process( sl->pid, WRITER ); if ( proc != NULL ) { tr = find_thread_with_id( proc, sl->tid ); if ( tr != NULL ) set_thread_state( tr, THREAD_RUNNING ); commit_process( proc ); } sl = sl->next; free( tmp ); } global_sems[ sem_id ].waiting_list = NULL; global_sems[ sem_id ].sem_id = -1; // DELETED! release_spinlock( & global_sems_lock ); return 0; }
void thread_pool_attached_executor<Scheduler>::add_at( boost::chrono::steady_clock::time_point const& abs_time, closure_type && f, char const* description, threads::thread_stacksize stacksize, error_code& ec) { if (stacksize == threads::thread_stacksize_default) stacksize = stacksize_; // create new thread thread_id_type id = register_thread_nullary( std::move(f), description, suspended, false, priority_, get_next_thread_num(), stacksize, ec); if (ec) return; HPX_ASSERT(invalid_thread_id != id); // would throw otherwise // now schedule new thread for execution set_thread_state(id, abs_time); }
void _random_shutdown( void ) { int i, size; if( _random_mutex ) mutex_lock( _random_mutex ); for( i = 0, size = array_size( _random_state ); i < size; ++i ) memory_deallocate( _random_state[i] ); array_deallocate( _random_available_state ); array_deallocate( _random_state ); set_thread_state( 0 ); if( _random_mutex ) { mutex_unlock( _random_mutex ); mutex_deallocate( _random_mutex ); } }
int destroy_local_semaphore( struct process *proc, int sem_id ) { struct sem_link *sl = NULL; struct sem_link *tmp = NULL; struct thread *tr = NULL; if ( sem_id < 0 ) return -1; if ( sem_id >= LOCAL_SEM_COUNT ) return -1; acquire_spinlock( & (proc->sems_lock) ); if ( proc->sems[ sem_id ].sem_id != sem_id ) { release_spinlock( & (proc->sems_lock) ); return -1; } // Tell the waiting guys to go away. sl = proc->sems[ sem_id ].waiting_list; while ( sl != NULL ) { tmp = sl; tr = find_thread_with_id( proc, sl->tid ); if ( tr != NULL ) set_thread_state( tr, THREAD_RUNNING ); sl = sl->next; free( tmp ); } proc->sems[ sem_id ].waiting_list = NULL; proc->sems[ sem_id ].sem_id = -1; // DELETED! release_spinlock( & (proc->sems_lock) ); return 0; }
static unsigned int* _random_thread_allocate( void ) { unsigned int* buffer; mutex_lock( _random_mutex ); //Grab a free state buffer or allocate if none available if( !array_size( _random_available_state ) ) { buffer = _random_allocate_buffer(); array_push( _random_available_state, buffer ); } else { buffer = _random_available_state[ array_size( _random_available_state ) - 1 ]; array_pop( _random_available_state ); } mutex_unlock( _random_mutex ); set_thread_state( buffer ); return buffer; }
int signal_global_semaphore( struct thread* tr, int sem_id ) { struct sem_link *sl; struct process *proc; struct thread *target; acquire_spinlock( & global_sems_lock ); if ( global_sems[ sem_id ].sem_id != sem_id ) { release_spinlock( & global_sems_lock ); return -1; } global_sems[ sem_id ].count -= 1; // wake up any waiting threads sl = global_sems[ sem_id ].waiting_list; if ( sl != NULL ) { proc = checkout_process( sl->pid, WRITER ); if ( proc != NULL ) { target = find_thread_with_id( proc, sl->tid ); if ( target != NULL ) set_thread_state( target, THREAD_RUNNING ); commit_process( proc ); } global_sems[ sem_id ].waiting_list = sl->next; free( sl ); } release_spinlock( & ( global_sems_lock ) ); return 0; }
int begin_wait_process( int pid, int *rc ) { int success = -1; struct wait_info *nw = NULL; struct process *proc; proc = checkout_process( pid, WRITER ); if ( proc == NULL ) return -1; nw = (struct wait_info*)malloc( sizeof(struct wait_info) ); nw->next = NULL; nw->prev = NULL; nw->pid = current_pid(); nw->tid = current_tid(); nw->success = -1; // Assume failure from the very beginning. nw->rc = -1; // Now we insert it into the wait list. if ( proc->waits != NULL ) proc->waits->prev = nw; nw->next = proc->waits; proc->waits = nw; // ----------------------------- commit_process( proc ); // ------ Now we go to sleep ------------- proc = checkout_process( current_pid(), WRITER ); ASSERT( proc != NULL ); current_thread()->active_wait = nw; // Save our active wait. disable_interrupts(); atomic_dec( &(proc->kernel_threads) ); set_thread_state( current_thread(), THREAD_WAITING ); commit_process( proc ); enable_interrupts(); sched_yield(); atomic_inc( &(proc->kernel_threads) ); // Secure this thread. // Get our process back. proc = checkout_process( current_pid(), WRITER ); ASSERT( proc != NULL ); current_thread()->active_wait = NULL; commit_process( proc ); // We're back. Return the correct info. *rc = nw->rc; success = nw->success; // nw should have been unlinked by the scheduler. // waiter should have active_wait cleared by the // scheduler as well. // we just need to delete it. free( nw ); /// \todo active_waits for threads. return success; }
int begin_wait_thread( int pid, int tid, int *rc ) { int success = -1; int size; struct wait_info *nw = NULL; struct process *proc; struct thread *tr; ASSERT( pid == current_pid() ); proc = checkout_process( pid, WRITER ); ASSERT( proc != NULL ); tr = find_thread_with_id( proc, tid ); if ( tr == NULL ) { commit_process( proc ); return -1; } // -------------------------------- size = sizeof(struct wait_info); nw = (struct wait_info*)malloc( size ); nw->next = NULL; nw->prev = NULL; nw->pid = current_pid(); nw->tid = current_tid(); nw->success = -1; // Assume failure from the very beginning. nw->rc = -1; current_thread()->active_wait = nw; // Set our active wait information. // Now we insert it into the wait list. if ( tr->waits != NULL ) tr->waits->prev = nw; nw->next = tr->waits; tr->waits = nw; // ----------------------------- commit_process( proc ); // ------ Now we go to sleep ------------- proc = checkout_process( current_pid(), WRITER ); if ( proc == NULL ) { /// \todo freak out and handle stuff properly return -1; } disable_interrupts(); atomic_dec( &(proc->kernel_threads) ); set_thread_state( current_thread(), THREAD_WAITING ); commit_process( proc ); enable_interrupts(); sched_yield(); // Release! // Secure ourselves. atomic_inc( &(proc->kernel_threads) ); // Get our process back. proc = checkout_process( current_pid(), WRITER ); if ( proc == NULL ) return -1; current_thread()->active_wait = NULL; commit_process( proc ); // We're back. Return the correct info. *rc = nw->rc; success = nw->success; // nw should have been unlinked by the scheduler. // waiter should have active_wait cleared by the // scheduler as well. // we just need to delete it. free( nw ); return success; }
static void audio_reset(struct ao *ao) { set_thread_state(ao, WASAPI_THREAD_RESET); }
int wait_local_semaphore( struct thread* tr, int sem_id ) { struct process *proc = NULL; struct sem_link *sl = NULL; struct sem_link *tmp = NULL; if ( sem_id < 0 ) return -1; if ( sem_id >= LOCAL_SEM_COUNT ) return -1; proc = tr->process; acquire_spinlock( & (proc->sems_lock) ); // Valid semaphore? if ( proc->sems[ sem_id ].sem_id != sem_id ) { release_spinlock( & (proc->sems_lock) ); return -1; } // Insert this thread into the waiting list and wait, if required. if ( proc->sems[ sem_id ].count == proc->sems[ sem_id ].capacity ) { sl = (struct sem_link*)malloc( sizeof( struct sem_link ) ); sl->tid = tr->tid; sl->pid = proc->pid; sl->next = NULL; if ( proc->sems[ sem_id ].waiting_list == NULL ) proc->sems[ sem_id ].waiting_list = sl; else { tmp = proc->sems[ sem_id ].waiting_list; while ( tmp->next != NULL ) tmp = tmp->next; tmp->next = sl; } // Now wait... disable_interrupts(); set_thread_state( tr, THREAD_SEMAPHORE ); release_spinlock( & (proc->sems_lock) ); enable_interrupts(); sched_yield(); // wait proper.. won't come back for a while. acquire_spinlock( & (proc->sems_lock) ); if ( proc->sems[ sem_id ].sem_id != sem_id ) { release_spinlock( & (proc->sems_lock) ); return -1; // Must have died... damn. } } proc->sems[ sem_id ].count += 1; release_spinlock( & (proc->sems_lock) ); return 0; }
static void audio_resume(struct ao *ao) { set_thread_state(ao, WASAPI_THREAD_RESUME); }
static void undo_init_new_thread(struct thread *th, init_thread_data *scribble) { int lock_ret; /* Kludge: Changed the order of some steps between the safepoint/ * non-safepoint versions of this code. Can we unify this more? */ #ifdef LISP_FEATURE_SB_SAFEPOINT block_blockable_signals(0); gc_alloc_update_page_tables(BOXED_PAGE_FLAG, &th->alloc_region); #if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32) gc_alloc_update_page_tables(BOXED_PAGE_FLAG, &th->sprof_alloc_region); #endif pop_gcing_safety(&scribble->safety); lock_ret = pthread_mutex_lock(&all_threads_lock); gc_assert(lock_ret == 0); unlink_thread(th); lock_ret = pthread_mutex_unlock(&all_threads_lock); gc_assert(lock_ret == 0); #else /* Block GC */ block_blockable_signals(0); set_thread_state(th, STATE_DEAD); /* SIG_STOP_FOR_GC is blocked and GC might be waiting for this * thread, but since we are already dead it won't wait long. */ lock_ret = pthread_mutex_lock(&all_threads_lock); gc_assert(lock_ret == 0); gc_alloc_update_page_tables(BOXED_PAGE_FLAG, &th->alloc_region); #if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32) gc_alloc_update_page_tables(BOXED_PAGE_FLAG, &th->sprof_alloc_region); #endif unlink_thread(th); pthread_mutex_unlock(&all_threads_lock); gc_assert(lock_ret == 0); #endif arch_os_thread_cleanup(th); #ifndef LISP_FEATURE_SB_SAFEPOINT os_sem_destroy(th->state_sem); os_sem_destroy(th->state_not_running_sem); os_sem_destroy(th->state_not_stopped_sem); #endif #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER mach_lisp_thread_destroy(th); #endif #if defined(LISP_FEATURE_WIN32) int i; for (i = 0; i< (int) (sizeof(th->private_events.events)/ sizeof(th->private_events.events[0])); ++i) { CloseHandle(th->private_events.events[i]); } TlsSetValue(OUR_TLS_INDEX,NULL); #endif /* Undo the association of the current pthread to its `struct thread', * such that we can call arch_os_get_current_thread() later in this * thread and cleanly get back NULL. */ #ifdef LISP_FEATURE_GCC_TLS current_thread = NULL; #else pthread_setspecific(specials, NULL); #endif }
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { struct rt_sigframe *frame; int err = 0; int signal; frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); if (regs->depc > 64) panic ("Double exception sys_sigreturn\n"); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; signal = current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap && sig < 32 ? current_thread_info()->exec_domain->signal_invmap[sig] : sig; err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->areg[1]), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Create sys_rt_sigreturn syscall in stack frame */ err |= gen_return_code(frame->retcode, USE_RT_SIGRETURN); if (err) goto give_sigsegv; /* Create signal handler execution context. * Return context not modified until this point. */ set_thread_state(regs, frame, frame->retcode, ka->sa.sa_handler, signal, &frame->info, &frame->uc); /* Set access mode to USER_DS. Nomenclature is outdated, but * functionality is used in uaccess.h */ set_fs(USER_DS); #if DEBUG_SIG printk("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08x\n", current->comm, current->pid, signal, frame, regs->pc); #endif return; give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); }
static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) { struct sigframe *frame; int err = 0; int signal; frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); if (regs->depc > 64) { printk("!!!!!!! DEPC !!!!!!!\n"); return; } if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; signal = current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap && sig < 32 ? current_thread_info()->exec_domain->signal_invmap[sig] : sig; err |= setup_sigcontext(&frame->sc, &frame->cpstate, regs, set->sig[0]); if (_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } /* Create sys_sigreturn syscall in stack frame */ err |= gen_return_code(frame->retcode, USE_SIGRETURN); if (err) goto give_sigsegv; /* Create signal handler execution context. * Return context not modified until this point. */ set_thread_state(regs, frame, frame->retcode, ka->sa.sa_handler, signal, &frame->sc, NULL); /* Set access mode to USER_DS. Nomenclature is outdated, but * functionality is used in uaccess.h */ set_fs(USER_DS); #if DEBUG_SIG printk("SIG deliver (%s:%d): signal=%d sp=%p pc=%08x\n", current->comm, current->pid, signal, frame, regs->pc); #endif return; give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); }
static int control_exclusive(struct ao *ao, enum aocontrol cmd, void *arg) { struct wasapi_state *state = ao->priv; switch (cmd) { case AOCONTROL_GET_VOLUME: case AOCONTROL_SET_VOLUME: if (!state->pEndpointVolumeProxy || !(state->vol_hw_support & ENDPOINT_HARDWARE_SUPPORT_VOLUME)) { return CONTROL_FALSE; } float volume; switch (cmd) { case AOCONTROL_GET_VOLUME: IAudioEndpointVolume_GetMasterVolumeLevelScalar( state->pEndpointVolumeProxy, &volume); *(ao_control_vol_t *)arg = (ao_control_vol_t){ .left = 100.0f * volume, .right = 100.0f * volume, }; return CONTROL_OK; case AOCONTROL_SET_VOLUME: volume = ((ao_control_vol_t *)arg)->left / 100.f; IAudioEndpointVolume_SetMasterVolumeLevelScalar( state->pEndpointVolumeProxy, volume, NULL); return CONTROL_OK; } case AOCONTROL_GET_MUTE: case AOCONTROL_SET_MUTE: if (!state->pEndpointVolumeProxy || !(state->vol_hw_support & ENDPOINT_HARDWARE_SUPPORT_MUTE)) { return CONTROL_FALSE; } BOOL mute; switch (cmd) { case AOCONTROL_GET_MUTE: IAudioEndpointVolume_GetMute(state->pEndpointVolumeProxy, &mute); *(bool *)arg = mute; return CONTROL_OK; case AOCONTROL_SET_MUTE: mute = *(bool *)arg; IAudioEndpointVolume_SetMute(state->pEndpointVolumeProxy, mute, NULL); return CONTROL_OK; } case AOCONTROL_HAS_PER_APP_VOLUME: return CONTROL_FALSE; default: return CONTROL_UNKNOWN; } } static int control_shared(struct ao *ao, enum aocontrol cmd, void *arg) { struct wasapi_state *state = ao->priv; if (!state->pAudioVolumeProxy) return CONTROL_UNKNOWN; float volume; BOOL mute; switch(cmd) { case AOCONTROL_GET_VOLUME: ISimpleAudioVolume_GetMasterVolume(state->pAudioVolumeProxy, &volume); *(ao_control_vol_t *)arg = (ao_control_vol_t){ .left = 100.0f * volume, .right = 100.0f * volume, }; return CONTROL_OK; case AOCONTROL_SET_VOLUME: volume = ((ao_control_vol_t *)arg)->left / 100.f; ISimpleAudioVolume_SetMasterVolume(state->pAudioVolumeProxy, volume, NULL); return CONTROL_OK; case AOCONTROL_GET_MUTE: ISimpleAudioVolume_GetMute(state->pAudioVolumeProxy, &mute); *(bool *)arg = mute; return CONTROL_OK; case AOCONTROL_SET_MUTE: mute = *(bool *)arg; ISimpleAudioVolume_SetMute(state->pAudioVolumeProxy, mute, NULL); return CONTROL_OK; case AOCONTROL_HAS_PER_APP_VOLUME: return CONTROL_TRUE; default: return CONTROL_UNKNOWN; } } static int control(struct ao *ao, enum aocontrol cmd, void *arg) { struct wasapi_state *state = ao->priv; // common to exclusive and shared switch (cmd) { case AOCONTROL_UPDATE_STREAM_TITLE: if (!state->pSessionControlProxy) return CONTROL_FALSE; wchar_t *title = mp_from_utf8(NULL, (char*)arg); wchar_t *tmp = NULL; // There is a weird race condition in the IAudioSessionControl itself -- // it seems that *sometimes* the SetDisplayName does not take effect and // it still shows the old title. Use this loop to insist until it works. do { IAudioSessionControl_SetDisplayName(state->pSessionControlProxy, title, NULL); SAFE_RELEASE(tmp, CoTaskMemFree(tmp)); IAudioSessionControl_GetDisplayName(state->pSessionControlProxy, &tmp); } while (lstrcmpW(title, tmp)); SAFE_RELEASE(tmp, CoTaskMemFree(tmp)); talloc_free(title); return CONTROL_OK; } return state->opt_exclusive ? control_exclusive(ao, cmd, arg) : control_shared(ao, cmd, arg); } static void audio_reset(struct ao *ao) { set_thread_state(ao, WASAPI_THREAD_RESET); } static void audio_resume(struct ao *ao) { set_thread_state(ao, WASAPI_THREAD_RESUME); }
void handle_sigint(int signum) { log_message(RL_NOTICE,"%s:SIGINT received, stopping %s thread",__FUNCTION__,get_thread_type_str(st_main.type)); /* Cannot stop_thread on main, since it's not pthread-ed */ //~ stop_thread(&st_main); set_thread_state(&st_main, CS_STOP, NULL); }
int main(int argc, char **argv) { /* Slave threads */ sgcomm_thread *st_rd; // Reader sgcomm_thread *st_tx; // Transmitter shared_buffer *sbtx; // shared buffer for read+transmit /* Reader message parameters */ char *fmtstr = "/mnt/disks/%u/%u/data/%s"; char *pattern_read = "input.vdif"; char *host = "localhost"; uint16_t port = 61234; int n_mod = 4; int mod_list[4] = { 1, 2, 3, 4}; int n_disk = 8; int disk_list_read[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; int disk_list_write[8] = { 1, 0, 2, 3, 4, 5, 6, 7 }; /* Transmitter message parameters */ if (argc > 1) pattern_read = argv[1]; if (argc > 2) fmtstr = argv[2]; if (argc > 3) host = argv[3]; if (argc > 4) port = atoi(argv[4]); log_message(RL_NOTICE,"%s:Using input file '%s' matching pattern '%s'",__FUNCTION__,pattern_read,fmtstr); log_message(RL_NOTICE,"%s:Transmitting to %s:%u",__FUNCTION__,host,port); /* This thread */ sgcomm_thread *st = &st_main; ctrl_state state; log_message(RL_DEBUG,"%s:Creating shared buffer",__FUNCTION__); /* Initialize shared data buffer */ sbtx = create_shared_buffer(SHARED_BUFFER_SIZE_TX); if (sbtx == NULL) set_thread_state(st,CS_ERROR,"%s(%d):Cannot create shared buffer for read+transmit",__FUNCTION__,__LINE__); log_message(RL_DEBUG,"%s:Creating slave threads",__FUNCTION__); /* Create thread instances */ st_rd = create_thread(TT_READER); if (st_rd == NULL) set_thread_state(st,CS_ERROR,"%s(%d):Cannot create reader thread",__FUNCTION__,__LINE__); st_tx = create_thread(TT_TRANSMITTER); if (st_tx == NULL) set_thread_state(st,CS_ERROR,"%s(%d):Cannot create transmitter thread",__FUNCTION__,__LINE__); log_message(RL_DEBUG,"%s:Initializing thread messages",__FUNCTION__); /* Initialize thread messages */ init_reader_msg((reader_msg *)st_rd->type_msg, sbtx, pattern_read, fmtstr, mod_list, n_mod, disk_list_read, n_disk); init_transmitter_msg((transmitter_msg *)st_tx->type_msg, sbtx, host, port); /* Start transmitter thread */ if (start_thread(st_tx) != 0) set_thread_state(st,CS_ERROR,"%s(%d):Cannot start transmitter thread",__FUNCTION__,__LINE__); /* Pause, then see if transmitter has error, if so, abort */ usleep(MAIN_WAIT_PERIOD_US); if ((get_thread_state(st_tx,&state) == 0) && (state >= CS_STOP)) { set_thread_state(st,CS_ERROR,"%s(%d):Transmitter terminated prematurely, aborting start.",__FUNCTION__,__LINE__); } else { if (start_thread(st_rd) != 0) set_thread_state(st,CS_ERROR,"%s(%d):Cannot start reader thread",__FUNCTION__,__LINE__); } //~ log_message(RL_DEBUG,"%s:Entering main thread run loop",__FUNCTION__); if ((get_thread_state(st,&state) == 0) && !(state >= CS_STOP)) set_thread_state(st,CS_RUN,"%s:Thread running",__FUNCTION__); while ((get_thread_state(st,&state) == 0) && !(state >= CS_STOP)) { // TODO: do something usleep(MAIN_WAIT_PERIOD_US); /* If any thread has a problem, stop all of them */ if ( ((get_thread_state(st_rd,&state) == 0) && (state >= CS_ERROR)) || ((get_thread_state(st_tx,&state) == 0) && (state >= CS_ERROR)) ) { // TODO: Some cleanup? break; } /* If all threads are stopped, break */ if ( ((get_thread_state(st_rd,&state) == 0) && (state >= CS_STOP)) && ((get_thread_state(st_tx,&state) == 0) && (state >= CS_STOP)) ) { log_message(RL_NOTICE,"%s:All threads stopped of their own volition",__FUNCTION__); break; } /* If reader thread is done, stop transmitter */ if ( (get_thread_state(st_rd,&state) == 0) && (state >= CS_STOP) && (get_thread_state(st_tx,&state) == 0) && (state < CS_STOP)) { log_message(RL_NOTICE,"%s:Reader is done, stop transmitter",__FUNCTION__); /* Two wait periods should be enough - reader is the only * other thread that can cause transmitter to wait on a * resource, and then it will only be a single wait. */ usleep(MAIN_WAIT_PERIOD_US); usleep(MAIN_WAIT_PERIOD_US); if (stop_thread(st_tx) != 0) set_thread_state(st,CS_ERROR,"%s(%d):Cannot stop transmitter thread",__FUNCTION__,__LINE__); } } log_message(RL_DEBUG,"%s:Stopping slave threads",__FUNCTION__); /* Stop slave threads on tx side */ if ( (get_thread_state(st_rd,&state) == 0) && (state < CS_STOP) && (state > CS_INIT) && stop_thread(st_rd) != 0) set_thread_state(st,CS_ERROR,"%s(%d):Cannot stop reader thread",__FUNCTION__,__LINE__); log_message(RL_DEBUGVVV,"%s:Reader thread stopped",__FUNCTION__); if ( (get_thread_state(st_tx,&state) == 0) && (state < CS_STOP) && (state > CS_INIT) && stop_thread(st_tx) != 0) set_thread_state(st,CS_ERROR,"%s(%d):Cannot stop transmitter thread",__FUNCTION__,__LINE__); log_message(RL_DEBUGVVV,"%s:Transmitter thread stopped",__FUNCTION__); log_message(RL_DEBUG,"%s:Destroying shared buffer",__FUNCTION__); /* Destroy shared data buffer */ if (destroy_shared_buffer(&sbtx) != 0) set_thread_state(st,CS_ERROR,"%s(%d):Cannot destroy shared buffer for read+transmit",__FUNCTION__,__LINE__); log_message(RL_DEBUG,"%s:Destroying slave threads",__FUNCTION__); /* Destroy threads */ destroy_thread(&st_rd); destroy_thread(&st_tx); log_message(RL_DEBUG,"%s:Everything is done, goodbye",__FUNCTION__); /* That's all folks! */ // TODO: Report that we're done return EXIT_SUCCESS; }