int vlc_cond_timedwait (vlc_cond_t *condvar, vlc_mutex_t *p_mutex, mtime_t deadline) { struct timespec ts = mtime_to_ts (deadline); vlc_thread_t th = thread; int (*cb)(pthread_cond_t *, pthread_mutex_t *, const struct timespec *); if (th != NULL) { vlc_testcancel (); if (vlc_mutex_trylock (&th->lock) == 0) { th->cond = &condvar->cond; vlc_mutex_unlock (&th->lock); } else { /* The lock is already held by another thread. * => That other thread has just cancelled this one. */ vlc_testcancel (); /* Cancellation did not occur even though this thread is cancelled. * => Cancellation is disabled. */ th = NULL; } } switch (condvar->clock) { case CLOCK_REALTIME: cb = pthread_cond_timedwait; break; case CLOCK_MONOTONIC: cb = pthread_cond_timedwait_monotonic_np; break; default: assert (0); } int val = cb (&condvar->cond, p_mutex, &ts); if (val != ETIMEDOUT) VLC_THREAD_ASSERT ("timed-waiting on condition"); if (th != NULL) { if (vlc_mutex_trylock (&th->lock) == 0) { thread->cond = NULL; vlc_mutex_unlock (&th->lock); } /* Else: This thread was cancelled and is cancellable. vlc_testcancel() will take of it right there: */ vlc_testcancel(); } return val; }
void mwait (mtime_t deadline) { mtime_t delay; vlc_testcancel(); while ((delay = (deadline - mdate())) > 0) { delay /= 1000; if (unlikely(delay > 0x7fffffff)) delay = 0x7fffffff; vlc_Sleep (delay); vlc_testcancel(); } }
int vlc_mwait_i11e(mtime_t deadline) { vlc_interrupt_t *ctx = vlc_threadvar_get(vlc_interrupt_var); if (ctx == NULL) return mwait(deadline), 0; vlc_cond_t wait; vlc_cond_init(&wait); int ret = vlc_interrupt_prepare(ctx, vlc_mwait_i11e_wake, &wait); if (ret) { vlc_cond_destroy(&wait); vlc_testcancel(); return ret; } vlc_mutex_lock(&ctx->lock); vlc_cleanup_push(vlc_mwait_i11e_cleanup, ctx); while (!ctx->interrupted && vlc_cond_timedwait(&wait, &ctx->lock, deadline) == 0); vlc_cleanup_pop(); vlc_mutex_unlock(&ctx->lock); ret = vlc_interrupt_finish(ctx); vlc_cond_destroy(&wait); return ret; }
static void *SigThread (void *data) { intf_thread_t *obj = data; sigset_t set; int signum; sigemptyset (&set); if (!ignored (SIGHUP)) /* <- needed to handle nohup properly */ sigaddset (&set, SIGHUP); sigaddset (&set, SIGINT); sigaddset (&set, SIGQUIT); sigaddset (&set, SIGTERM); sigaddset (&set, SIGCHLD); do { while (sigwait (&set, &signum)); #ifdef __APPLE__ /* In Mac OS X up to 10.5 sigwait (among others) is not a pthread * cancellation point */ vlc_testcancel(); #endif /* Hack for Qt QProcess */ if (signum == SIGCHLD) { struct sigaction act; sigaction (signum, NULL, &act); if ((act.sa_flags & SA_SIGINFO) || (act.sa_handler != SIG_DFL)) { msg_Err (obj, "signal %d overriden (%p)", signum, act.sa_handler); #ifdef __GLIBC__ Dl_info info; if (dladdr (act.sa_handler, &info)) msg_Err (obj, " %s(%s)[%p]", info.dli_fname ? info.dli_fname : "?", info.dli_sname ? info.dli_sname : "?", info.dli_saddr); #endif if (!(act.sa_flags & SA_SIGINFO) && (act.sa_handler != SIG_IGN)) act.sa_handler (signum); } } } while (signum == SIGCHLD); msg_Err (obj, "Caught %s signal, exiting...", strsignal (signum)); libvlc_Quit (obj->p_libvlc); /* After 3 seconds, fallback to normal signal handling */ msleep (3 * CLOCK_FREQ); pthread_sigmask (SIG_UNBLOCK, &set, NULL); for (;;) pause (); }
int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex, mtime_t deadline) { DWORD result; do { vlc_testcancel (); mtime_t total = (deadline - mdate ())/1000; if( total < 0 ) total = 0; DWORD delay = (total > 0x7fffffff) ? 0x7fffffff : total; LeaveCriticalSection (&p_mutex->mutex); result = WaitForSingleObjectEx (*p_condvar, delay, TRUE); EnterCriticalSection (&p_mutex->mutex); } while (result == WAIT_IO_COMPLETION); assert (result != WAIT_ABANDONED); assert (result != WAIT_FAILED); ResetEvent (*p_condvar); return (result == WAIT_OBJECT_0) ? 0 : ETIMEDOUT; }
void vlc_sem_wait (vlc_sem_t *sem) { ULONG rc; do { vlc_testcancel (); DosRequestMutexSem(sem->wait_mutex, SEM_INDEFINITE_WAIT); rc = vlc_WaitForSingleObject (sem->hev, SEM_INDEFINITE_WAIT ); if (!rc) { DosRequestMutexSem(sem->count_mutex, SEM_INDEFINITE_WAIT); sem->count--; if (sem->count == 0) { ULONG ulPost; DosResetEventSem(sem->hev, &ulPost); } DosReleaseMutexSem(sem->count_mutex); } DosReleaseMutexSem(sem->wait_mutex); } while (rc == ERROR_INTERRUPT); }
int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout) { struct timespec tsbuf, *ts; sigset_t set; int canc, ret; if (timeout != -1) { div_t d = div (timeout, 1000); tsbuf.tv_sec = d.quot; tsbuf.tv_nsec = d.rem * 1000000; ts = &tsbuf; } else ts = NULL; pthread_sigmask (SIG_BLOCK, NULL, &set); sigdelset (&set, SIGRTMIN); canc = vlc_savecancel (); ret = ppoll (fds, nfds, ts, &set); vlc_restorecancel (canc); vlc_testcancel (); return ret; }
static void Run( fingerprinter_thread_t *p_fingerprinter ) { fingerprinter_sys_t *p_sys = p_fingerprinter->p_sys; /* main loop */ for (;;) { vlc_mutex_lock( &p_sys->processing.lock ); mutex_cleanup_push( &p_sys->processing.lock ); vlc_cond_timedwait( &p_sys->incoming_queue_filled, &p_sys->processing.lock, mdate() + 1000000 ); vlc_cleanup_run(); QueueIncomingRequests( p_sys ); vlc_mutex_lock( &p_sys->processing.lock ); // L0 mutex_cleanup_push( &p_sys->processing.lock ); vlc_cleanup_push( cancelRun, p_sys ); // C1 //** for ( p_sys->i = 0 ; p_sys->i < vlc_array_count( p_sys->processing.queue ); p_sys->i++ ) { fingerprint_request_t *p_data = vlc_array_item_at_index( p_sys->processing.queue, p_sys->i ); acoustid_fingerprint_t acoustid_print; memset( &acoustid_print , 0, sizeof(acoustid_fingerprint_t) ); vlc_cleanup_push( clearPrint, &acoustid_print ); // C2 p_sys->psz_uri = input_item_GetURI( p_data->p_item ); if ( p_sys->psz_uri ) { /* overwrite with hint, as in this case, fingerprint's session will be truncated */ if ( p_data->i_duration ) acoustid_print.i_duration = p_data->i_duration; DoFingerprint( VLC_OBJECT(p_fingerprinter), p_sys, &acoustid_print ); DoAcoustIdWebRequest( VLC_OBJECT(p_fingerprinter), &acoustid_print ); fill_metas_with_results( p_data, &acoustid_print ); FREENULL( p_sys->psz_uri ); } vlc_cleanup_run( ); // C2 /* copy results */ vlc_mutex_lock( &p_sys->results.lock ); vlc_array_append( p_sys->results.queue, p_data ); vlc_mutex_unlock( &p_sys->results.lock ); vlc_testcancel(); } if ( vlc_array_count( p_sys->processing.queue ) ) { var_TriggerCallback( p_fingerprinter, "results-available" ); vlc_array_clear( p_sys->processing.queue ); } vlc_cleanup_pop( ); // C1 //** vlc_cleanup_run(); // L0 } }
void vlc_join (vlc_thread_t th, void **result) { do vlc_testcancel (); while (vlc_WaitForSingleObject (th->id, INFINITE) == WAIT_IO_COMPLETION); if (result != NULL) *result = th->data; CloseHandle (th->id); free (th); }
void vlc_sem_wait (vlc_sem_t *sem) { DWORD result; do { vlc_testcancel (); result = vlc_WaitForSingleObject (*sem, INFINITE); } while (result == WAIT_IO_COMPLETION); }
void vlc_cond_wait (vlc_cond_t *condvar, vlc_mutex_t *p_mutex) { vlc_thread_t th = thread; if (th != NULL) { vlc_testcancel (); if (vlc_mutex_trylock (&th->lock) == 0) { th->cond = &condvar->cond; vlc_mutex_unlock (&th->lock); } else { /* The lock is already held by another thread. * => That other thread has just cancelled this one. */ vlc_testcancel (); /* Cancellation did not occur even though this thread is cancelled. * => Cancellation is disabled. */ th = NULL; } } int val = pthread_cond_wait (&condvar->cond, p_mutex); VLC_THREAD_ASSERT ("waiting on condition"); if (th != NULL) { if (vlc_mutex_trylock (&th->lock) == 0) { thread->cond = NULL; vlc_mutex_unlock (&th->lock); } /* Else: This thread was cancelled and is cancellable. vlc_testcancel() will take of it right there: */ vlc_testcancel(); } }
void vlc_join (vlc_thread_t handle, void **result) { do vlc_testcancel (); while (WaitForSingleObjectEx (handle->handle, INFINITE, TRUE) == WAIT_IO_COMPLETION); CloseHandle (handle->handle); if (result) *result = handle->data; #ifdef UNDER_CE CloseHandle (handle->cancel_event); #endif free (handle); }
void vlc_sem_wait (vlc_sem_t *sem) { HANDLE handle = vlc_sem_handle(sem); DWORD result; do { vlc_testcancel (); result = WaitForSingleObjectEx(handle, INFINITE, TRUE); /* Semaphore abandoned would be a bug. */ assert(result != WAIT_ABANDONED_0); } while (result == WAIT_IO_COMPLETION || result == WAIT_FAILED); }
void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex) { DWORD result; do { vlc_testcancel (); LeaveCriticalSection (&p_mutex->mutex); result = WaitForSingleObjectEx (*p_condvar, INFINITE, TRUE); EnterCriticalSection (&p_mutex->mutex); } while (result == WAIT_IO_COMPLETION); assert (result != WAIT_ABANDONED); /* another thread failed to cleanup! */ assert (result != WAIT_FAILED); ResetEvent (*p_condvar); }
void vlc_join (vlc_thread_t th, void **result) { ULONG rc; do { vlc_testcancel(); rc = vlc_WaitForSingleObject( th->done_event, SEM_INDEFINITE_WAIT ); } while( rc == ERROR_INTERRUPT ); if (result != NULL) *result = th->data; DosCloseEventSem( th->cancel_event ); DosCloseEventSem( th->done_event ); free( th ); }
int vlc_sem_wait_i11e(vlc_sem_t *sem) { vlc_interrupt_t *ctx = vlc_threadvar_get(vlc_interrupt_var); if (ctx == NULL) return vlc_sem_wait(sem), 0; int ret = vlc_interrupt_prepare(ctx, vlc_interrupt_sem, sem); if (ret) { vlc_testcancel(); return ret; } vlc_cleanup_push(vlc_interrupt_cleanup, ctx); vlc_sem_wait(sem); vlc_cleanup_pop(); return vlc_interrupt_finish(ctx); }
int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex, mtime_t deadline) { ULONG ulTimeout; ULONG ulPost; ULONG rc; if (!p_condvar->hev) { /* FIXME FIXME FIXME */ msleep (50000); return; } do { vlc_testcancel(); mtime_t total; switch (p_condvar->clock) { case CLOCK_REALTIME: /* FIXME? sub-second precision */ total = CLOCK_FREQ * time (NULL); break; default: assert (p_condvar->clock == CLOCK_MONOTONIC); total = mdate(); break; } total = (deadline - total) / 1000; if( total < 0 ) total = 0; ulTimeout = ( total > 0x7fffffff ) ? 0x7fffffff : total; vlc_mutex_unlock (p_mutex); rc = vlc_WaitForSingleObject( p_condvar->hev, ulTimeout ); vlc_mutex_lock (p_mutex); } while( rc == ERROR_INTERRUPT ); DosResetEventSem( p_condvar->hev, &ulPost ); return rc ? ETIMEDOUT : 0; }
int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex, mtime_t deadline) { DWORD result; if (!p_condvar->handle) { /* FIXME FIXME FIXME */ msleep (50000); return 0; } do { vlc_testcancel (); mtime_t total; switch (p_condvar->clock) { case CLOCK_REALTIME: /* FIXME? sub-second precision */ total = CLOCK_FREQ * time (NULL); break; default: assert (p_condvar->clock == CLOCK_MONOTONIC); total = mdate(); break; } total = (deadline - total) / 1000; if( total < 0 ) total = 0; DWORD delay = (total > 0x7fffffff) ? 0x7fffffff : total; vlc_mutex_unlock (p_mutex); result = vlc_WaitForSingleObject (p_condvar->handle, delay); vlc_mutex_lock (p_mutex); } while (result == WAIT_IO_COMPLETION); ResetEvent (p_condvar->handle); return (result == WAIT_OBJECT_0) ? 0 : ETIMEDOUT; }
void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex) { DWORD result; if (!p_condvar->clock) { /* FIXME FIXME FIXME */ msleep (50000); return; } do { vlc_testcancel (); vlc_mutex_unlock (p_mutex); result = vlc_WaitForSingleObject (p_condvar->handle, INFINITE); vlc_mutex_lock (p_mutex); } while (result == WAIT_IO_COMPLETION); ResetEvent (p_condvar->handle); }
void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex) { ULONG ulPost; ULONG rc; if (!p_condvar->hev) { /* FIXME FIXME FIXME */ msleep (50000); return; } do { vlc_testcancel(); vlc_mutex_unlock (p_mutex); rc = vlc_WaitForSingleObject( p_condvar->hev, SEM_INDEFINITE_WAIT ); vlc_mutex_lock (p_mutex); } while( rc == ERROR_INTERRUPT ); DosResetEventSem( p_condvar->hev, &ulPost ); }
int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout) { size_t setsize = sizeof (fd_set) + nfds * sizeof (SOCKET); fd_set *rdset = malloc (setsize); fd_set *wrset = malloc (setsize); fd_set *exset = malloc (setsize); struct timeval tv = { 0, 0 }; int val; if (unlikely(rdset == NULL || wrset == NULL || exset == NULL)) { free (rdset); free (wrset); free (exset); errno = ENOMEM; return -1; } /* Winsock FD_SET uses FD_SETSIZE in its expansion */ #undef FD_SETSIZE #define FD_SETSIZE (nfds) resume: val = -1; vlc_testcancel (); FD_ZERO (rdset); FD_ZERO (wrset); FD_ZERO (exset); for (unsigned i = 0; i < nfds; i++) { int fd = fds[i].fd; if (val < fd) val = fd; /* With POSIX, FD_SET & FD_ISSET are not defined if fd is negative or * bigger or equal than FD_SETSIZE. That is one of the reasons why VLC * uses poll() rather than select(). Most POSIX systems implement * fd_set has a bit field with no sanity checks. This is especially bad * on systems (such as BSD) that have no process open files limit by * default, such that it is quite feasible to get fd >= FD_SETSIZE. * The next instructions will result in a buffer overflow if run on * a POSIX system, and the later FD_ISSET would perform an undefined * memory read. * * With Winsock, fd_set is a table of integers. This is awfully slow. * However, FD_SET and FD_ISSET silently and safely discard excess * entries. Here, overflow cannot happen anyway: fd_set of adequate * size are allocated. * Note that Vista has a much nicer WSAPoll(), but Mingw does not * support it yet. */ if (fds[i].events & POLLIN) FD_SET ((SOCKET)fd, rdset); if (fds[i].events & POLLOUT) FD_SET ((SOCKET)fd, wrset); if (fds[i].events & POLLPRI) FD_SET ((SOCKET)fd, exset); } #ifndef HAVE_ALERTABLE_SELECT # warning FIXME! Fix cancellation and remove this crap. if ((timeout < 0) || (timeout > 50)) { tv.tv_sec = 0; tv.tv_usec = 50000; } else #endif if (timeout >= 0) { div_t d = div (timeout, 1000); tv.tv_sec = d.quot; tv.tv_usec = d.rem * 1000; } val = select (val + 1, rdset, wrset, exset, /*(timeout >= 0) ?*/ &tv /*: NULL*/); #ifndef HAVE_ALERTABLE_SELECT if (val == 0) { if (timeout > 0) timeout -= (timeout > 50) ? 50 : timeout; if (timeout != 0) goto resume; } #endif if (val == -1) return -1; for (unsigned i = 0; i < nfds; i++) { int fd = fds[i].fd; fds[i].revents = (FD_ISSET (fd, rdset) ? POLLIN : 0) | (FD_ISSET (fd, wrset) ? POLLOUT : 0) | (FD_ISSET (fd, exset) ? POLLPRI : 0); } free (exset); free (wrset); free (rdset); return val; }
/***************************************************************************** * Run : *****************************************************************************/ static void *Run( void *opaque ) { fingerprinter_thread_t *p_fingerprinter = opaque; fingerprinter_sys_t *p_sys = p_fingerprinter->p_sys; vlc_mutex_lock( &p_sys->processing.lock ); mutex_cleanup_push( &p_sys->processing.lock ); /* main loop */ for (;;) { msleep( CLOCK_FREQ ); QueueIncomingRequests( p_sys ); vlc_testcancel(); for ( size_t i = 0 ; i < vlc_array_count( &p_sys->processing.queue ); i++ ) { int canc = vlc_savecancel(); fingerprint_request_t *p_data = vlc_array_item_at_index( &p_sys->processing.queue, i ); char *psz_uri = input_item_GetURI( p_data->p_item ); if ( psz_uri != NULL ) { acoustid_fingerprint_t acoustid_print; memset( &acoustid_print , 0, sizeof (acoustid_print) ); /* overwrite with hint, as in this case, fingerprint's session will be truncated */ if ( p_data->i_duration ) acoustid_print.i_duration = p_data->i_duration; DoFingerprint( p_fingerprinter, &acoustid_print, psz_uri ); free( psz_uri ); DoAcoustIdWebRequest( VLC_OBJECT(p_fingerprinter), &acoustid_print ); fill_metas_with_results( p_data, &acoustid_print ); for( unsigned j = 0; j < acoustid_print.results.count; j++ ) free_acoustid_result_t( &acoustid_print.results.p_results[j] ); if( acoustid_print.results.count ) free( acoustid_print.results.p_results ); free( acoustid_print.psz_fingerprint ); } vlc_restorecancel(canc); /* copy results */ vlc_mutex_lock( &p_sys->results.lock ); vlc_array_append( &p_sys->results.queue, p_data ); vlc_mutex_unlock( &p_sys->results.lock ); vlc_testcancel(); } if ( vlc_array_count( &p_sys->processing.queue ) ) { var_TriggerCallback( p_fingerprinter, "results-available" ); vlc_array_clear( &p_sys->processing.queue ); } } vlc_cleanup_pop(); vlc_assert_unreachable(); }
static void Run(intf_thread_t *p_intf) { intf_sys_t *p_sys = p_intf->p_sys; input_thread_t *p_input = NULL; playlist_t *p_playlist = pl_Get(p_intf); int *pi_fd, i_listen = 0, i_err; p_intf->p_sys->p_playlist = p_playlist; for (pi_fd = p_sys->pi_socket; *pi_fd != -1; pi_fd++) i_listen++; for (; vlc_object_alive(p_intf);) { vlc_value_t val; struct pollfd fd[i_listen + 2]; vlc_testcancel(); if (p_input == NULL) { p_input = playlist_CurrentInput(p_playlist); if (p_input) { var_AddCallback(p_input, "intf-event", InputEvent, p_intf); } } else { if (p_input->b_dead || !vlc_object_alive(p_input)) { var_DelCallback(p_input, "intf-event", InputEvent, p_intf); vlc_object_release(p_input); p_input = NULL; } } memset(&fd, 0, sizeof(fd[0]) * (i_listen + 1)); if (p_sys->i_socket == -1) { for (int i = 0; i < i_listen; i++) { fd[i].fd = p_sys->pi_socket[i]; fd[i].events = POLLIN; fd[i].revents = 0; } } else { fd[0].fd = p_sys->i_wakeup[0]; fd[0].events = POLLIN; fd[0].revents = 0; fd[1].fd = p_sys->i_socket; fd[1].events = POLLIN | (p_sys->i_write_length > 0 ? POLLOUT : 0); fd[1].revents = 0; } i_err = poll(fd, (p_sys->i_socket != -1) ? 2 : i_listen, -1); if (i_err < 0) { msg_Dbg(p_intf, "poll() failed"); vlc_object_kill(p_intf); break; } if (i_err == 0) continue; if (p_sys->i_socket == -1) { for (int i = 0; i < i_listen; i++) { if (fd[i].revents & POLLIN) { int client = net_AcceptSingle(VLC_OBJECT(p_intf), fd[i].fd); if (client == -1) continue; p_sys->i_socket = client; break; } } } else { if (fd[0].revents & POLLIN) { char ch; read(fd[0].fd, &ch, 1); } if (fd[1].revents & (POLLERR|POLLHUP|POLLNVAL)) { net_Close(fd[0].fd); p_sys->i_socket = -1; msg_Dbg(VLC_OBJECT(p_intf), "connection error"); continue; } ssize_t i_len, i_test; if (fd[1].revents & POLLIN) { //msg_Dbg(VLC_OBJECT(p_intf), "poll in"); bool b_line = false; while ((i_len = recv(fd[1].fd, p_sys->p_read_buffer + p_sys->i_read_offset, 1, 0)) > 0) { char ch; ch = p_sys->p_read_buffer[p_sys->i_read_offset]; switch (ch) { case '\r': case '\n': p_sys->p_read_buffer[p_sys->i_read_offset] = '\0'; b_line = true; break; case '\0': b_line = true; break; default: break; } p_sys->i_read_offset++; if (p_sys->i_read_offset == sizeof(p_sys->p_read_buffer) && !b_line) { net_Close(p_sys->i_socket); p_sys->i_socket = -1; msg_Dbg(VLC_OBJECT(p_intf), "input is too long, close connection"); break; } } if (b_line && strlen(p_sys->p_read_buffer)) { p_sys->i_read_offset = 0; //msg_Dbg(VLC_OBJECT(p_intf), "%s\n", p_sys->p_read_buffer); ProcessCommand(p_intf, p_sys->p_read_buffer); } if(i_len == 0) { net_Close(p_sys->i_socket); p_sys->i_socket = -1; msg_Dbg(VLC_OBJECT(p_intf), "connection is closed by client"); } } if (fd[1].revents & POLLOUT) { vlc_mutex_lock(&p_sys->o_write_lock); if (p_sys->i_write_length) { int i_first, i_second; i_first = sizeof(p_sys->p_write_buffer) - p_sys->i_write_offset; i_second = (p_sys->i_write_offset + p_sys->i_write_length) % sizeof(p_sys->p_write_buffer); i_test = 0; if (i_first >= p_sys->i_write_length) i_len = send(fd[1].fd, p_sys->p_write_buffer + p_sys->i_write_offset, p_sys->i_write_length, 0); else { i_len = send(fd[1].fd, p_sys->p_write_buffer + p_sys->i_write_offset, i_first, 0); if (i_len == i_first) i_test = send(fd[1].fd, p_sys->p_write_buffer, i_second, 0); if (i_test > 0) i_len += i_test; } if (i_len > 0) { p_sys->i_write_offset += i_len; p_sys->i_write_offset %= sizeof(p_sys->p_write_buffer); p_sys->i_write_length -= i_len; if (p_sys->i_write_length == 0) p_sys->i_write_offset = 0; } } vlc_mutex_unlock(&p_sys->o_write_lock); } } } }