Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
4a742a33
Commit
4a742a33
authored
Oct 07, 2012
by
Rafaël Carré
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
android: threads support
parent
314fd505
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
513 additions
and
5 deletions
+513
-5
include/vlc_threads.h
include/vlc_threads.h
+24
-3
src/Makefile.am
src/Makefile.am
+1
-1
src/android/thread.c
src/android/thread.c
+487
-0
src/libvlc.h
src/libvlc.h
+1
-1
No files found.
include/vlc_threads.h
View file @
4a742a33
...
...
@@ -42,6 +42,15 @@
# define pthread_sigmask sigprocmask
#elif defined( __ANDROID__ )
/* pthreads subset without pthread_cancel() */
# define LIBVLC_NEED_SEMAPHORE
# define LIBVLC_NEED_RWLOCK
# include <unistd.h>
/* _POSIX_SPIN_LOCKS */
# include <pthread.h>
# include <poll.h>
#else
/* pthreads (like Linux & BSD) */
# define LIBVLC_USE_PTHREAD 1
# define LIBVLC_USE_PTHREAD_CANCEL 1
...
...
@@ -73,7 +82,7 @@
# define VLC_THREAD_PRIORITY_OUTPUT 22
# define VLC_THREAD_PRIORITY_HIGHEST 22
#elif defined(LIBVLC_USE_PTHREAD)
#elif defined(LIBVLC_USE_PTHREAD)
|| defined(__ANDROID__)
# define VLC_THREAD_PRIORITY_LOW 0
# define VLC_THREAD_PRIORITY_INPUT 10
# define VLC_THREAD_PRIORITY_AUDIO 5
...
...
@@ -116,7 +125,17 @@
* Type definitions
*****************************************************************************/
#if defined (LIBVLC_USE_PTHREAD)
#if defined (__ANDROID__)
typedef
struct
vlc_thread
*
vlc_thread_t
;
typedef
pthread_mutex_t
vlc_mutex_t
;
#define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER
typedef
pthread_cond_t
vlc_cond_t
;
#define VLC_STATIC_COND PTHREAD_COND_INITIALIZER
typedef
pthread_key_t
vlc_threadvar_t
;
typedef
struct
vlc_timer
*
vlc_timer_t
;
#elif defined (LIBVLC_USE_PTHREAD)
typedef
pthread_t
vlc_thread_t
;
typedef
pthread_mutex_t
vlc_mutex_t
;
#define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER
...
...
@@ -332,7 +351,7 @@ VLC_API int vlc_savecancel(void);
VLC_API
void
vlc_restorecancel
(
int
state
);
VLC_API
void
vlc_testcancel
(
void
);
#if defined (LIBVLC_USE_PTHREAD_CANCEL)
#if defined (LIBVLC_USE_PTHREAD_CANCEL)
|| defined(__ANDROID__)
/**
* Registers a new procedure to run if the thread is cancelled (or otherwise
* exits prematurely). Any call to vlc_cleanup_push() <b>must</b> paired with a
...
...
@@ -383,7 +402,9 @@ struct vlc_cleanup_t
vlc_control_cancel (VLC_CLEANUP_POP); \
vlc_cleanup_data.proc (vlc_cleanup_data.data); \
} while (0)
#endif
/* LIBVLC_USE_PTHREAD_CANCEL || __ANDROID__ */
#if !defined (LIBVLC_USE_PTHREAD_CANCEL)
/* poll() with cancellation */
static
inline
int
vlc_poll
(
struct
pollfd
*
fds
,
unsigned
nfds
,
int
timeout
)
{
...
...
src/Makefile.am
View file @
4a742a33
...
...
@@ -259,9 +259,9 @@ SOURCES_libvlc_darwin = \
SOURCES_libvlc_android
=
\
android/dirs.c
\
android/thread.c
\
posix/filesystem.c
\
posix/plugin.c
\
posix/thread.c
\
posix/timer.c
\
posix/linux_cpu.c
\
posix/linux_specific.c
\
...
...
src/android/thread.c
0 → 100644
View file @
4a742a33
/*****************************************************************************
* thread.c : android pthread back-end for LibVLC
*****************************************************************************
* Copyright (C) 1999-2012 VLC authors and VideoLAN
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* Gildas Bazin <gbazin@netcourrier.com>
* Clément Sténac
* Rémi Denis-Courmont
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_atomic.h>
#include "libvlc.h"
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
/* fsync() */
#include <pthread.h>
#include <sched.h>
#include <android/log.h>
#include <sys/syscall.h>
/* __NR_gettid */
/* FIXME: Android has a monotonic clock
* XXX : how to use it with pthread_cond_wait() ? */
# warning Monotonic clock not available. Expect timing issues.
/* helper */
static
struct
timespec
mtime_to_ts
(
mtime_t
date
)
{
lldiv_t
d
=
lldiv
(
date
,
CLOCK_FREQ
);
struct
timespec
ts
=
{
d
.
quot
,
d
.
rem
*
(
1000000000
/
CLOCK_FREQ
)
};
return
ts
;
}
/* debug */
#define vlc_assert(x) do { \
if (unlikely(!x)) { \
__android_log_print(ANDROID_LOG_ERROR, "vlc", "assert failed %s:%d: %s", \
__FILE__, __LINE__, #x \
); \
abort(); \
} \
} while(0)
#ifndef NDEBUG
static
void
vlc_thread_fatal
(
const
char
*
action
,
int
error
,
const
char
*
function
,
const
char
*
file
,
unsigned
line
)
{
char
buf
[
1000
];
const
char
*
msg
;
switch
(
strerror_r
(
error
,
buf
,
sizeof
(
buf
)))
{
case
0
:
msg
=
buf
;
break
;
case
ERANGE
:
/* should never happen */
msg
=
"unknown (too big to display)"
;
break
;
default:
msg
=
"unknown (invalid error number)"
;
break
;
}
__android_log_print
(
ANDROID_LOG_ERROR
,
"vlc"
,
"LibVLC fatal error %s (%d) in thread %d "
"at %s:%u in %s
\n
Error message: %s
\n
"
,
action
,
error
,
syscall
(
__NR_gettid
),
file
,
line
,
function
,
msg
);
abort
();
}
# define VLC_THREAD_ASSERT( action ) \
if (unlikely(val)) \
vlc_thread_fatal (action, val, __func__, __FILE__, __LINE__)
#else
# define VLC_THREAD_ASSERT( action ) ((void)val)
#endif
/* mutexes */
void
vlc_mutex_init
(
vlc_mutex_t
*
p_mutex
)
{
pthread_mutexattr_t
attr
;
pthread_mutexattr_init
(
&
attr
);
#ifdef NDEBUG
pthread_mutexattr_settype
(
&
attr
,
PTHREAD_MUTEX_DEFAULT
);
#else
pthread_mutexattr_settype
(
&
attr
,
PTHREAD_MUTEX_ERRORCHECK
);
#endif
pthread_mutex_init
(
p_mutex
,
&
attr
);
pthread_mutexattr_destroy
(
&
attr
);
}
void
vlc_mutex_init_recursive
(
vlc_mutex_t
*
p_mutex
)
{
pthread_mutexattr_t
attr
;
pthread_mutexattr_init
(
&
attr
);
pthread_mutexattr_settype
(
&
attr
,
PTHREAD_MUTEX_RECURSIVE
);
pthread_mutex_init
(
p_mutex
,
&
attr
);
pthread_mutexattr_destroy
(
&
attr
);
}
void
vlc_mutex_destroy
(
vlc_mutex_t
*
p_mutex
)
{
int
val
=
pthread_mutex_destroy
(
p_mutex
);
VLC_THREAD_ASSERT
(
"destroying mutex"
);
}
#ifndef NDEBUG
void
vlc_assert_locked
(
vlc_mutex_t
*
p_mutex
)
{
vlc_assert
(
pthread_mutex_lock
(
p_mutex
)
==
EDEADLK
);
}
#endif
void
vlc_mutex_lock
(
vlc_mutex_t
*
p_mutex
)
{
int
val
=
pthread_mutex_lock
(
p_mutex
);
VLC_THREAD_ASSERT
(
"locking mutex"
);
}
int
vlc_mutex_trylock
(
vlc_mutex_t
*
p_mutex
)
{
int
val
=
pthread_mutex_trylock
(
p_mutex
);
if
(
val
!=
EBUSY
)
VLC_THREAD_ASSERT
(
"locking mutex"
);
return
val
;
}
void
vlc_mutex_unlock
(
vlc_mutex_t
*
p_mutex
)
{
int
val
=
pthread_mutex_unlock
(
p_mutex
);
VLC_THREAD_ASSERT
(
"unlocking mutex"
);
}
struct
vlc_thread
{
pthread_t
thread
;
pthread_cond_t
*
cond
;
/// Non-null if thread waiting on cond
vlc_mutex_t
lock
;
/// Protects cond
void
*
(
*
entry
)(
void
*
);
void
*
data
;
vlc_atomic_t
killable
;
vlc_atomic_t
killed
;
vlc_atomic_t
finished
;
bool
detached
;
};
static
__thread
struct
vlc_thread
*
thread
=
NULL
;
void
vlc_threads_setup
(
libvlc_int_t
*
p_libvlc
)
{
(
void
)
p_libvlc
;
}
static
void
*
andro_Thread
(
void
*
data
)
{
thread
=
data
;
void
*
ret
=
thread
->
entry
(
thread
->
data
);
if
(
thread
->
detached
)
{
/* release thread handle */
vlc_mutex_destroy
(
&
thread
->
lock
);
free
(
thread
);
}
else
{
vlc_atomic_set
(
&
thread
->
finished
,
true
);
/* thread handle will be freed when vlc_join() is called */
}
return
ret
;
}
/* cond */
void
vlc_cond_init
(
vlc_cond_t
*
p_condvar
)
{
if
(
unlikely
(
pthread_cond_init
(
p_condvar
,
NULL
)))
abort
();
}
void
vlc_cond_init_daytime
(
vlc_cond_t
*
p_condvar
)
{
vlc_cond_init
(
p_condvar
);
}
void
vlc_cond_destroy
(
vlc_cond_t
*
p_condvar
)
{
int
val
=
pthread_cond_destroy
(
p_condvar
);
VLC_THREAD_ASSERT
(
"destroying condition"
);
}
void
vlc_cond_signal
(
vlc_cond_t
*
p_condvar
)
{
int
val
=
pthread_cond_signal
(
p_condvar
);
VLC_THREAD_ASSERT
(
"signaling condition variable"
);
}
void
vlc_cond_broadcast
(
vlc_cond_t
*
p_condvar
)
{
pthread_cond_broadcast
(
p_condvar
);
}
void
vlc_cond_wait
(
vlc_cond_t
*
p_condvar
,
vlc_mutex_t
*
p_mutex
)
{
if
(
thread
)
{
vlc_testcancel
();
vlc_mutex_lock
(
&
thread
->
lock
);
thread
->
cond
=
p_condvar
;
vlc_mutex_unlock
(
&
thread
->
lock
);
}
int
val
=
pthread_cond_wait
(
p_condvar
,
p_mutex
);
if
(
thread
)
{
vlc_mutex_lock
(
&
thread
->
lock
);
thread
->
cond
=
NULL
;
vlc_mutex_unlock
(
&
thread
->
lock
);
vlc_testcancel
();
}
VLC_THREAD_ASSERT
(
"waiting on condition"
);
}
int
vlc_cond_timedwait
(
vlc_cond_t
*
p_condvar
,
vlc_mutex_t
*
p_mutex
,
mtime_t
deadline
)
{
struct
timespec
ts
=
mtime_to_ts
(
deadline
);
if
(
thread
)
{
vlc_testcancel
();
vlc_mutex_lock
(
&
thread
->
lock
);
thread
->
cond
=
p_condvar
;
vlc_mutex_unlock
(
&
thread
->
lock
);
}
int
val
=
pthread_cond_timedwait
(
p_condvar
,
p_mutex
,
&
ts
);
if
(
val
!=
ETIMEDOUT
)
VLC_THREAD_ASSERT
(
"timed-waiting on condition"
);
if
(
thread
)
{
vlc_mutex_lock
(
&
thread
->
lock
);
thread
->
cond
=
NULL
;
vlc_mutex_unlock
(
&
thread
->
lock
);
vlc_testcancel
();
}
return
val
;
}
/* pthread */
static
int
vlc_clone_attr
(
vlc_thread_t
*
th
,
pthread_attr_t
*
attr
,
void
*
(
*
entry
)
(
void
*
),
void
*
data
,
int
priority
)
{
int
ret
;
sigset_t
oldset
;
{
sigset_t
set
;
sigemptyset
(
&
set
);
sigdelset
(
&
set
,
SIGHUP
);
sigaddset
(
&
set
,
SIGINT
);
sigaddset
(
&
set
,
SIGQUIT
);
sigaddset
(
&
set
,
SIGTERM
);
sigaddset
(
&
set
,
SIGPIPE
);
/* We don't want this one, really! */
pthread_sigmask
(
SIG_BLOCK
,
&
set
,
&
oldset
);
}
(
void
)
priority
;
vlc_thread_t
thread
=
malloc
(
sizeof
(
*
thread
));
if
(
unlikely
(
thread
==
NULL
))
{
if
(
attr
)
pthread_attr_destroy
(
attr
);
return
ENOMEM
;
}
vlc_atomic_set
(
&
thread
->
killable
,
true
);
vlc_atomic_set
(
&
thread
->
killed
,
false
);
vlc_atomic_set
(
&
thread
->
finished
,
false
);
int
state
=
PTHREAD_CREATE_JOINABLE
;
if
(
attr
)
pthread_attr_getdetachstate
(
attr
,
&
state
);
thread
->
detached
=
state
==
PTHREAD_CREATE_DETACHED
;
thread
->
cond
=
NULL
;
thread
->
entry
=
entry
;
thread
->
data
=
data
;
vlc_mutex_init
(
&
thread
->
lock
);
*
th
=
thread
;
ret
=
pthread_create
(
&
thread
->
thread
,
attr
,
andro_Thread
,
thread
);
pthread_sigmask
(
SIG_SETMASK
,
&
oldset
,
NULL
);
if
(
attr
)
pthread_attr_destroy
(
attr
);
return
ret
;
}
int
vlc_clone
(
vlc_thread_t
*
th
,
void
*
(
*
entry
)
(
void
*
),
void
*
data
,
int
priority
)
{
pthread_attr_t
attr
;
pthread_attr_init
(
&
attr
);
return
vlc_clone_attr
(
th
,
&
attr
,
entry
,
data
,
priority
);
}
void
vlc_join
(
vlc_thread_t
handle
,
void
**
result
)
{
vlc_testcancel
();
while
(
!
vlc_atomic_get
(
&
handle
->
finished
))
msleep
(
CLOCK_FREQ
/
100
);
int
val
=
pthread_join
(
handle
->
thread
,
result
);
VLC_THREAD_ASSERT
(
"joining thread"
);
vlc_mutex_destroy
(
&
handle
->
lock
);
free
(
handle
);
}
int
vlc_clone_detach
(
vlc_thread_t
*
th
,
void
*
(
*
entry
)
(
void
*
),
void
*
data
,
int
priority
)
{
vlc_thread_t
dummy
;
pthread_attr_t
attr
;
if
(
th
==
NULL
)
th
=
&
dummy
;
pthread_attr_init
(
&
attr
);
pthread_attr_setdetachstate
(
&
attr
,
PTHREAD_CREATE_DETACHED
);
return
vlc_clone_attr
(
th
,
&
attr
,
entry
,
data
,
priority
);
}
int
vlc_set_priority
(
vlc_thread_t
th
,
int
priority
)
{
(
void
)
th
;
(
void
)
priority
;
return
VLC_SUCCESS
;
}
void
vlc_cancel
(
vlc_thread_t
thread_id
)
{
vlc_atomic_set
(
&
thread_id
->
killed
,
true
);
if
(
!
vlc_atomic_get
(
&
thread_id
->
killable
))
return
;
vlc_mutex_lock
(
&
thread_id
->
lock
);
vlc_cond_t
*
cond
=
thread_id
->
cond
;
if
(
cond
)
pthread_cond_broadcast
(
cond
);
vlc_mutex_unlock
(
&
thread_id
->
lock
);
}
int
vlc_savecancel
(
void
)
{
if
(
!
thread
)
/* not created by VLC, can't be cancelled */
return
true
;
int
oldstate
=
vlc_atomic_get
(
&
thread
->
killable
);
vlc_atomic_set
(
&
thread
->
killable
,
false
);
return
oldstate
;
}
void
vlc_restorecancel
(
int
state
)
{
if
(
!
thread
)
/* not created by VLC, can't be cancelled */
return
;
vlc_atomic_set
(
&
thread
->
killable
,
state
);
}
void
vlc_testcancel
(
void
)
{
if
(
!
thread
)
/* not created by VLC, can't be cancelled */
return
;
if
(
!
vlc_atomic_get
(
&
thread
->
killable
))
return
;
if
(
!
vlc_atomic_get
(
&
thread
->
killed
))
return
;
vlc_atomic_set
(
&
thread
->
finished
,
true
);
pthread_exit
(
NULL
);
}
/* threadvar */
int
vlc_threadvar_create
(
vlc_threadvar_t
*
key
,
void
(
*
destr
)
(
void
*
))
{
return
pthread_key_create
(
key
,
destr
);
}
void
vlc_threadvar_delete
(
vlc_threadvar_t
*
p_tls
)
{
pthread_key_delete
(
*
p_tls
);
}
int
vlc_threadvar_set
(
vlc_threadvar_t
key
,
void
*
value
)
{
return
pthread_setspecific
(
key
,
value
);
}
void
*
vlc_threadvar_get
(
vlc_threadvar_t
key
)
{
return
pthread_getspecific
(
key
);
}
/* time */
mtime_t
mdate
(
void
)
{
struct
timespec
ts
;
if
(
unlikely
(
clock_gettime
(
CLOCK_REALTIME
,
&
ts
)
!=
0
))
abort
();
return
(
INT64_C
(
1000000
)
*
ts
.
tv_sec
)
+
(
ts
.
tv_nsec
/
1000
);
}
#undef mwait
void
mwait
(
mtime_t
deadline
)
{
deadline
-=
mdate
();
if
(
deadline
>
0
)
msleep
(
deadline
);
}
#undef msleep
void
msleep
(
mtime_t
delay
)
{
struct
timespec
ts
=
mtime_to_ts
(
delay
);
vlc_testcancel
();
for
(;;)
{
/* FIXME: drift */
struct
timespec
t
=
{
0
,
10
*
1000
*
1000
};
if
(
ts
.
tv_sec
<=
0
&&
t
.
tv_nsec
>
ts
.
tv_nsec
)
t
.
tv_nsec
=
ts
.
tv_nsec
;
while
(
nanosleep
(
&
t
,
&
t
)
==
-
1
)
{
vlc_testcancel
();
vlc_assert
(
errno
==
EINTR
);
}
ts
.
tv_nsec
-=
10
*
1000
*
1000
;
if
(
ts
.
tv_nsec
<
0
)
{
if
(
--
ts
.
tv_sec
<
0
)
return
;
ts
.
tv_nsec
+=
1000
*
1000
*
1000
;
}
}
}
/* cpu */
unsigned
vlc_GetCPUCount
(
void
)
{
return
sysconf
(
_SC_NPROCESSORS_CONF
);
}
src/libvlc.h
View file @
4a742a33
...
...
@@ -66,7 +66,7 @@ void vlc_threads_setup (libvlc_int_t *);
void
vlc_trace
(
const
char
*
fn
,
const
char
*
file
,
unsigned
line
);
#define vlc_backtrace() vlc_trace(__func__, __FILE__, __LINE__)
#if
defined (LIBVLC_USE_PTHREAD
) && !defined (NDEBUG)
#if
(defined (LIBVLC_USE_PTHREAD) || defined(__ANDROID__)
) && !defined (NDEBUG)
void
vlc_assert_locked
(
vlc_mutex_t
*
);
#else
# define vlc_assert_locked( m ) (void)m
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment