Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-2-2
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-2-2
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 @@
...
@@ -42,6 +42,15 @@
# define pthread_sigmask sigprocmask
# 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) */
#else
/* pthreads (like Linux & BSD) */
# define LIBVLC_USE_PTHREAD 1
# define LIBVLC_USE_PTHREAD 1
# define LIBVLC_USE_PTHREAD_CANCEL 1
# define LIBVLC_USE_PTHREAD_CANCEL 1
...
@@ -73,7 +82,7 @@
...
@@ -73,7 +82,7 @@
# define VLC_THREAD_PRIORITY_OUTPUT 22
# define VLC_THREAD_PRIORITY_OUTPUT 22
# define VLC_THREAD_PRIORITY_HIGHEST 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_LOW 0
# define VLC_THREAD_PRIORITY_INPUT 10
# define VLC_THREAD_PRIORITY_INPUT 10
# define VLC_THREAD_PRIORITY_AUDIO 5
# define VLC_THREAD_PRIORITY_AUDIO 5
...
@@ -116,7 +125,17 @@
...
@@ -116,7 +125,17 @@
* Type definitions
* 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_t
vlc_thread_t
;
typedef
pthread_mutex_t
vlc_mutex_t
;
typedef
pthread_mutex_t
vlc_mutex_t
;
#define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER
#define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER
...
@@ -332,7 +351,7 @@ VLC_API int vlc_savecancel(void);
...
@@ -332,7 +351,7 @@ VLC_API int vlc_savecancel(void);
VLC_API
void
vlc_restorecancel
(
int
state
);
VLC_API
void
vlc_restorecancel
(
int
state
);
VLC_API
void
vlc_testcancel
(
void
);
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
* 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
* exits prematurely). Any call to vlc_cleanup_push() <b>must</b> paired with a
...
@@ -383,7 +402,9 @@ struct vlc_cleanup_t
...
@@ -383,7 +402,9 @@ struct vlc_cleanup_t
vlc_control_cancel (VLC_CLEANUP_POP); \
vlc_control_cancel (VLC_CLEANUP_POP); \
vlc_cleanup_data.proc (vlc_cleanup_data.data); \
vlc_cleanup_data.proc (vlc_cleanup_data.data); \
} while (0)
} while (0)
#endif
/* LIBVLC_USE_PTHREAD_CANCEL || __ANDROID__ */
#if !defined (LIBVLC_USE_PTHREAD_CANCEL)
/* poll() with cancellation */
/* poll() with cancellation */
static
inline
int
vlc_poll
(
struct
pollfd
*
fds
,
unsigned
nfds
,
int
timeout
)
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 = \
...
@@ -259,9 +259,9 @@ SOURCES_libvlc_darwin = \
SOURCES_libvlc_android
=
\
SOURCES_libvlc_android
=
\
android/dirs.c
\
android/dirs.c
\
android/thread.c
\
posix/filesystem.c
\
posix/filesystem.c
\
posix/plugin.c
\
posix/plugin.c
\
posix/thread.c
\
posix/timer.c
\
posix/timer.c
\
posix/linux_cpu.c
\
posix/linux_cpu.c
\
posix/linux_specific.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 *);
...
@@ -66,7 +66,7 @@ void vlc_threads_setup (libvlc_int_t *);
void
vlc_trace
(
const
char
*
fn
,
const
char
*
file
,
unsigned
line
);
void
vlc_trace
(
const
char
*
fn
,
const
char
*
file
,
unsigned
line
);
#define vlc_backtrace() vlc_trace(__func__, __FILE__, __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
*
);
void
vlc_assert_locked
(
vlc_mutex_t
*
);
#else
#else
# define vlc_assert_locked( m ) (void)m
# 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