150 lines
2.9 KiB
C
150 lines
2.9 KiB
C
#define __USE_GNU
|
|
#include "tvheadend.h"
|
|
#include <fcntl.h>
|
|
#include <sys/types.h> /* See NOTES */
|
|
#include <sys/socket.h>
|
|
#include <sys/prctl.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
|
|
int
|
|
tvh_open(const char *pathname, int flags, mode_t mode)
|
|
{
|
|
int fd;
|
|
|
|
pthread_mutex_lock(&fork_lock);
|
|
fd = open(pathname, flags, mode);
|
|
if (fd != -1)
|
|
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
|
|
pthread_mutex_unlock(&fork_lock);
|
|
return fd;
|
|
}
|
|
|
|
|
|
int
|
|
tvh_socket(int domain, int type, int protocol)
|
|
{
|
|
int fd;
|
|
|
|
pthread_mutex_lock(&fork_lock);
|
|
fd = socket(domain, type, protocol);
|
|
if (fd != -1)
|
|
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
|
|
pthread_mutex_unlock(&fork_lock);
|
|
return fd;
|
|
}
|
|
|
|
int
|
|
tvh_pipe(int flags, th_pipe_t *p)
|
|
{
|
|
int fd[2], err;
|
|
pthread_mutex_lock(&fork_lock);
|
|
err = pipe(fd);
|
|
if (err != -1) {
|
|
fcntl(fd[0], F_SETFD, fcntl(fd[0], F_GETFD) | FD_CLOEXEC);
|
|
fcntl(fd[1], F_SETFD, fcntl(fd[1], F_GETFD) | FD_CLOEXEC);
|
|
fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | flags);
|
|
fcntl(fd[1], F_SETFL, fcntl(fd[1], F_GETFL) | flags);
|
|
p->rd = fd[0];
|
|
p->wr = fd[1];
|
|
}
|
|
pthread_mutex_unlock(&fork_lock);
|
|
return err;
|
|
}
|
|
|
|
void
|
|
tvh_pipe_close(th_pipe_t *p)
|
|
{
|
|
close(p->rd);
|
|
close(p->wr);
|
|
p->rd = -1;
|
|
p->wr = -1;
|
|
}
|
|
|
|
int
|
|
tvh_write(int fd, const void *buf, size_t len)
|
|
{
|
|
ssize_t c;
|
|
|
|
while (len) {
|
|
c = write(fd, buf, len);
|
|
if (c < 0) {
|
|
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
usleep(100);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
len -= c;
|
|
buf += c;
|
|
}
|
|
|
|
return len ? 1 : 0;
|
|
}
|
|
|
|
struct
|
|
thread_state {
|
|
void *(*run)(void*);
|
|
void *arg;
|
|
char name[17];
|
|
};
|
|
|
|
static void *
|
|
thread_wrapper ( void *p )
|
|
{
|
|
struct thread_state *ts = p;
|
|
|
|
/* Set name */
|
|
prctl(PR_SET_NAME, ts->name);
|
|
|
|
/* Run */
|
|
tvhdebug("thread", "created thread %ld [%s / %p(%p)]",
|
|
(long)pthread_self(), ts->name, ts->run, ts->arg);
|
|
void *r = ts->run(ts->arg);
|
|
free(ts);
|
|
|
|
return r;
|
|
}
|
|
|
|
int
|
|
tvhthread_create0
|
|
(pthread_t *thread, const pthread_attr_t *attr,
|
|
void *(*start_routine) (void *), void *arg, const char *name,
|
|
int detach)
|
|
{
|
|
int r;
|
|
struct thread_state *ts = calloc(1, sizeof(struct thread_state));
|
|
strncpy(ts->name, name, sizeof(ts->name));
|
|
ts->run = start_routine;
|
|
ts->arg = arg;
|
|
r = pthread_create(thread, attr, thread_wrapper, ts);
|
|
if (detach)
|
|
pthread_detach(*thread);
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* qsort_r wrapper for pre GLIBC 2.8
|
|
*/
|
|
|
|
#if !__GLIBC_PREREQ(2,8)
|
|
static __thread struct {
|
|
int (*cmp) ( const void *a, const void *b, void *p );
|
|
void *aux;
|
|
} qsort_r_data;
|
|
|
|
static int
|
|
qsort_r_wrap ( const void *a, const void *b )
|
|
{
|
|
return qsort_r_data.cmp(a, b, qsort_r_data.aux);
|
|
}
|
|
|
|
void
|
|
qsort_r(void *base, size_t nmemb, size_t size,
|
|
int (*cmp)(const void *, const void *, void *), void *aux)
|
|
{
|
|
qsort_r_data.cmp = cmp;
|
|
qsort_r_data.aux = aux;
|
|
qsort(base, nmemb, size, qsort_r_wrap);
|
|
}
|
|
#endif /* GLIBC < 2.8 */
|