mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
add CPU load limiter
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@176 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
c73a298f88
commit
4a9239f808
10 changed files with 392 additions and 40 deletions
2
doc/todo
2
doc/todo
|
|
@ -16,6 +16,8 @@
|
||||||
- automatic termination of daemon if unused
|
- automatic termination of daemon if unused
|
||||||
- add sample directory
|
- add sample directory
|
||||||
- paman: show scache and sample size
|
- paman: show scache and sample size
|
||||||
|
- add timing parameter to write callback of stream in client API
|
||||||
|
- add option for disabling module loading
|
||||||
|
|
||||||
** later ***
|
** later ***
|
||||||
- xmlrpc/http
|
- xmlrpc/http
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ AM_LIBADD=$(PTHREAD_LIBS) -lm
|
||||||
EXTRA_DIST = polypaudio.pa depmod.py esdcompat.sh.in
|
EXTRA_DIST = polypaudio.pa depmod.py esdcompat.sh.in
|
||||||
bin_PROGRAMS = polypaudio pacat pactl
|
bin_PROGRAMS = polypaudio pacat pactl
|
||||||
bin_SCRIPTS = esdcompat.sh
|
bin_SCRIPTS = esdcompat.sh
|
||||||
noinst_PROGRAMS = mainloop-test mainloop-test-glib mainloop-test-glib12 pacat-simple parec-simple
|
noinst_PROGRAMS = mainloop-test mainloop-test-glib mainloop-test-glib12 pacat-simple parec-simple cpulimit-test cpulimit-test2
|
||||||
|
|
||||||
polypconf_DATA=polypaudio.pa
|
polypconf_DATA=polypaudio.pa
|
||||||
|
|
||||||
|
|
@ -142,7 +142,8 @@ polypaudio_SOURCES = idxset.c idxset.h \
|
||||||
xmalloc.c xmalloc.h \
|
xmalloc.c xmalloc.h \
|
||||||
subscribe.h subscribe.c \
|
subscribe.h subscribe.c \
|
||||||
debug.h \
|
debug.h \
|
||||||
sound-file-stream.c sound-file-stream.h
|
sound-file-stream.c sound-file-stream.h \
|
||||||
|
cpulimit.c cpulimit.h
|
||||||
|
|
||||||
polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
|
polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
|
||||||
polypaudio_INCLUDES = $(INCLTDL)
|
polypaudio_INCLUDES = $(INCLTDL)
|
||||||
|
|
@ -387,6 +388,15 @@ mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES)
|
||||||
mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP
|
mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP
|
||||||
mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12.la
|
mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12.la
|
||||||
|
|
||||||
|
cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c
|
||||||
|
cpulimit_test_CFLAGS = $(AM_CFLAGS)
|
||||||
|
cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop.la
|
||||||
|
|
||||||
|
cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c
|
||||||
|
cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2
|
||||||
|
cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop.la
|
||||||
|
|
||||||
|
|
||||||
if BUILD_LIBPOLYPCORE
|
if BUILD_LIBPOLYPCORE
|
||||||
|
|
||||||
polypinclude_HEADERS+=cli-command.h\
|
polypinclude_HEADERS+=cli-command.h\
|
||||||
|
|
|
||||||
84
polyp/cpulimit-test.c
Normal file
84
polyp/cpulimit-test.c
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of polypaudio.
|
||||||
|
|
||||||
|
polypaudio is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published
|
||||||
|
by the Free Software Foundation; either version 2 of the License,
|
||||||
|
or (at your option) any later version.
|
||||||
|
|
||||||
|
polypaudio 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
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with polypaudio; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
USA.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include "cpulimit.h"
|
||||||
|
#include "mainloop.h"
|
||||||
|
|
||||||
|
#ifdef TEST2
|
||||||
|
#include "mainloop-signal.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static time_t start;
|
||||||
|
|
||||||
|
#ifdef TEST2
|
||||||
|
|
||||||
|
static void func(struct pa_mainloop_api *m, struct pa_signal_event *e, int sig, void *userdata) {
|
||||||
|
time_t now;
|
||||||
|
time(&now);
|
||||||
|
|
||||||
|
if ((now - start) >= 30) {
|
||||||
|
m->quit(m, 1);
|
||||||
|
fprintf(stderr, "Test failed\n");
|
||||||
|
} else
|
||||||
|
raise(SIGUSR1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
struct pa_mainloop *m;
|
||||||
|
|
||||||
|
m = pa_mainloop_new();
|
||||||
|
assert(m);
|
||||||
|
|
||||||
|
pa_cpu_limit_init(pa_mainloop_get_api(m));
|
||||||
|
|
||||||
|
time(&start);
|
||||||
|
|
||||||
|
#ifdef TEST2
|
||||||
|
pa_signal_init(pa_mainloop_get_api(m));
|
||||||
|
pa_signal_new(SIGUSR1, func, NULL);
|
||||||
|
raise(SIGUSR1);
|
||||||
|
pa_mainloop_run(m, NULL);
|
||||||
|
pa_signal_done();
|
||||||
|
#else
|
||||||
|
for (;;) {
|
||||||
|
time_t now;
|
||||||
|
time(&now);
|
||||||
|
|
||||||
|
if ((now - start) >= 30) {
|
||||||
|
fprintf(stderr, "Test failed\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pa_cpu_limit_done();
|
||||||
|
|
||||||
|
pa_mainloop_free(m);
|
||||||
|
|
||||||
|
}
|
||||||
175
polyp/cpulimit.c
Normal file
175
polyp/cpulimit.c
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of polypaudio.
|
||||||
|
|
||||||
|
polypaudio is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published
|
||||||
|
by the Free Software Foundation; either version 2 of the License,
|
||||||
|
or (at your option) any later version.
|
||||||
|
|
||||||
|
polypaudio 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
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with polypaudio; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
USA.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include "cpulimit.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* Utilize this much CPU time at most */
|
||||||
|
#define CPUTIME_PERCENT 70
|
||||||
|
|
||||||
|
#define CPUTIME_INTERVAL_SOFT (5)
|
||||||
|
#define CPUTIME_INTERVAL_HARD (2)
|
||||||
|
|
||||||
|
static time_t last_time = 0;
|
||||||
|
static int the_pipe[2] = {-1, -1};
|
||||||
|
static struct pa_mainloop_api *api = NULL;
|
||||||
|
static struct pa_io_event *io_event = NULL;
|
||||||
|
static struct sigaction sigaction_prev;
|
||||||
|
static int installed = 0;
|
||||||
|
|
||||||
|
static enum {
|
||||||
|
PHASE_IDLE,
|
||||||
|
PHASE_SOFT
|
||||||
|
} phase = PHASE_IDLE;
|
||||||
|
|
||||||
|
static void reset_cpu_time(int t) {
|
||||||
|
int r;
|
||||||
|
long n;
|
||||||
|
struct rlimit rl;
|
||||||
|
struct rusage ru;
|
||||||
|
|
||||||
|
r = getrusage(RUSAGE_SELF, &ru);
|
||||||
|
assert(r >= 0);
|
||||||
|
|
||||||
|
n = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec + t;
|
||||||
|
|
||||||
|
r = getrlimit(RLIMIT_CPU, &rl);
|
||||||
|
assert(r >= 0);
|
||||||
|
|
||||||
|
rl.rlim_cur = n;
|
||||||
|
r = setrlimit(RLIMIT_CPU, &rl);
|
||||||
|
assert(r >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_err(const char *p) {
|
||||||
|
pa_loop_write(2, p, strlen(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void signal_handler(int sig) {
|
||||||
|
assert(sig == SIGXCPU);
|
||||||
|
|
||||||
|
if (phase == PHASE_IDLE) {
|
||||||
|
time_t now;
|
||||||
|
char t[256];
|
||||||
|
|
||||||
|
time(&now);
|
||||||
|
|
||||||
|
snprintf(t, sizeof(t), "Using %0.1f%% CPU\n", (double)CPUTIME_INTERVAL_SOFT/(now-last_time)*100);
|
||||||
|
write_err(t);
|
||||||
|
|
||||||
|
if (CPUTIME_INTERVAL_SOFT >= ((now-last_time)*(double)CPUTIME_PERCENT/100)) {
|
||||||
|
static const char c = 'X';
|
||||||
|
|
||||||
|
write_err("Soft CPU time limit exhausted, terminating.\n");
|
||||||
|
|
||||||
|
/* Try a soft cleanup */
|
||||||
|
write(the_pipe[1], &c, sizeof(c));
|
||||||
|
phase = PHASE_SOFT;
|
||||||
|
reset_cpu_time(CPUTIME_INTERVAL_HARD);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Everything's fine */
|
||||||
|
reset_cpu_time(CPUTIME_INTERVAL_SOFT);
|
||||||
|
last_time = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (phase == PHASE_SOFT) {
|
||||||
|
write_err("Hard CPU time limit exhausted, terminating forcibly.\n");
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callback(struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) {
|
||||||
|
char c;
|
||||||
|
assert(m && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == the_pipe[0]);
|
||||||
|
read(the_pipe[0], &c, sizeof(c));
|
||||||
|
m->quit(m, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pa_cpu_limit_init(struct pa_mainloop_api *m) {
|
||||||
|
int r;
|
||||||
|
struct sigaction sa;
|
||||||
|
assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1);
|
||||||
|
|
||||||
|
time(&last_time);
|
||||||
|
|
||||||
|
if (pipe(the_pipe) < 0) {
|
||||||
|
fprintf(stderr, "pipe() failed: %s\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_make_nonblock_fd(the_pipe[0]);
|
||||||
|
pa_make_nonblock_fd(the_pipe[1]);
|
||||||
|
pa_fd_set_cloexec(the_pipe[0], 1);
|
||||||
|
pa_fd_set_cloexec(the_pipe[1], 1);
|
||||||
|
|
||||||
|
api = m;
|
||||||
|
io_event = api->io_new(m, the_pipe[0], PA_IO_EVENT_INPUT, callback, NULL);
|
||||||
|
|
||||||
|
phase = PHASE_IDLE;
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sa_handler = signal_handler;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
|
||||||
|
r = sigaction(SIGXCPU, &sa, &sigaction_prev);
|
||||||
|
assert(r >= 0);
|
||||||
|
|
||||||
|
installed = 1;
|
||||||
|
|
||||||
|
reset_cpu_time(CPUTIME_INTERVAL_SOFT);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pa_cpu_limit_done(void) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (io_event) {
|
||||||
|
assert(api);
|
||||||
|
api->io_free(io_event);
|
||||||
|
io_event = NULL;
|
||||||
|
api = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (the_pipe[0] >= 0)
|
||||||
|
close(the_pipe[0]);
|
||||||
|
if (the_pipe[1] >= 0)
|
||||||
|
close(the_pipe[1]);
|
||||||
|
the_pipe[0] = the_pipe[1] = -1;
|
||||||
|
|
||||||
|
if (installed) {
|
||||||
|
r = sigaction(SIGXCPU, &sigaction_prev, NULL);
|
||||||
|
assert(r >= 0);
|
||||||
|
installed = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
34
polyp/cpulimit.h
Normal file
34
polyp/cpulimit.h
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef foocpulimithfoo
|
||||||
|
#define foocpulimithfoo
|
||||||
|
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of polypaudio.
|
||||||
|
|
||||||
|
polypaudio is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published
|
||||||
|
by the Free Software Foundation; either version 2 of the License,
|
||||||
|
or (at your option) any later version.
|
||||||
|
|
||||||
|
polypaudio 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
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with polypaudio; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
USA.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include "mainloop-api.h"
|
||||||
|
|
||||||
|
/* This kills the polypaudio process if it eats more than 70% of the
|
||||||
|
* CPU time. This is build around setrlimit() and SIGXCPU. It is handy
|
||||||
|
* in case of using SCHED_FIFO which may freeze the whole machine */
|
||||||
|
|
||||||
|
int pa_cpu_limit_init(struct pa_mainloop_api *m);
|
||||||
|
void pa_cpu_limit_done(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
49
polyp/main.c
49
polyp/main.c
|
|
@ -43,6 +43,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "sioman.h"
|
#include "sioman.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
#include "cpulimit.h"
|
||||||
|
|
||||||
static struct pa_mainloop *mainloop;
|
static struct pa_mainloop *mainloop;
|
||||||
|
|
||||||
|
|
@ -54,15 +55,37 @@ static void drop_root(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
|
static const char* signal_name(int s) {
|
||||||
m->quit(m, 1);
|
switch(s) {
|
||||||
fprintf(stderr, __FILE__": got signal.\n");
|
case SIGINT: return "SIGINT";
|
||||||
|
case SIGTERM: return "SIGTERM";
|
||||||
|
case SIGUSR1: return "SIGUSR1";
|
||||||
|
case SIGUSR2: return "SIGUSR2";
|
||||||
|
case SIGXCPU: return "SIGXCPU";
|
||||||
|
case SIGPIPE: return "SIGPIPE";
|
||||||
|
default: return "UNKNOWN SIGNAL";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aux_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
|
static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
|
||||||
struct pa_core *c = userdata;
|
fprintf(stderr, __FILE__": got signal %s.\n", signal_name(sig));
|
||||||
assert(c);
|
|
||||||
pa_module_load(c, sig == SIGUSR1 ? "module-cli" : "module-cli-protocol-unix", NULL);
|
switch (sig) {
|
||||||
|
case SIGUSR1:
|
||||||
|
pa_module_load(userdata, "module-cli", NULL);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SIGUSR2:
|
||||||
|
pa_module_load(userdata, "module-cli-protocol-unix", NULL);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SIGINT:
|
||||||
|
case SIGTERM:
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Exiting.\n");
|
||||||
|
m->quit(m, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_pipe(int p[2]) {
|
static void close_pipe(int p[2]) {
|
||||||
|
|
@ -157,16 +180,19 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
r = pa_signal_init(pa_mainloop_get_api(mainloop));
|
r = pa_signal_init(pa_mainloop_get_api(mainloop));
|
||||||
assert(r == 0);
|
assert(r == 0);
|
||||||
pa_signal_new(SIGINT, exit_signal_callback, NULL);
|
pa_signal_new(SIGINT, signal_callback, c);
|
||||||
pa_signal_new(SIGTERM, exit_signal_callback, NULL);
|
pa_signal_new(SIGTERM, signal_callback, c);
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
c = pa_core_new(pa_mainloop_get_api(mainloop));
|
c = pa_core_new(pa_mainloop_get_api(mainloop));
|
||||||
assert(c);
|
assert(c);
|
||||||
|
|
||||||
pa_signal_new(SIGUSR1, aux_signal_callback, c);
|
pa_signal_new(SIGUSR1, signal_callback, c);
|
||||||
pa_signal_new(SIGUSR2, aux_signal_callback, c);
|
pa_signal_new(SIGUSR2, signal_callback, c);
|
||||||
|
|
||||||
|
r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop));
|
||||||
|
assert(r == 0);
|
||||||
|
|
||||||
buf = pa_strbuf_new();
|
buf = pa_strbuf_new();
|
||||||
assert(buf);
|
assert(buf);
|
||||||
r = pa_cli_command_execute(c, cmdline->cli_commands, buf, &cmdline->fail, &cmdline->verbose);
|
r = pa_cli_command_execute(c, cmdline->cli_commands, buf, &cmdline->fail, &cmdline->verbose);
|
||||||
|
|
@ -193,6 +219,7 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
pa_core_free(c);
|
pa_core_free(c);
|
||||||
|
|
||||||
|
pa_cpu_limit_done();
|
||||||
pa_signal_done();
|
pa_signal_done();
|
||||||
pa_mainloop_free(mainloop);
|
pa_mainloop_free(mainloop);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,33 +54,31 @@ static void signal_handler(int sig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) {
|
static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) {
|
||||||
|
ssize_t r;
|
||||||
|
int sig;
|
||||||
|
struct pa_signal_event*s;
|
||||||
assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]);
|
assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]);
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
ssize_t r;
|
|
||||||
int sig;
|
|
||||||
struct pa_signal_event*s;
|
|
||||||
|
|
||||||
if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) {
|
if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) {
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN)
|
||||||
return;
|
|
||||||
|
|
||||||
fprintf(stderr, "signal.c: read(): %s\n", strerror(errno));
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (r != sizeof(sig)) {
|
fprintf(stderr, "signal.c: read(): %s\n", strerror(errno));
|
||||||
fprintf(stderr, "signal.c: short read()\n");
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (s = signals; s; s = s->next)
|
|
||||||
if (s->sig == sig) {
|
|
||||||
assert(s->callback);
|
|
||||||
s->callback(a, s, sig, s->userdata);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (r != sizeof(sig)) {
|
||||||
|
fprintf(stderr, "signal.c: short read()\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s = signals; s; s = s->next)
|
||||||
|
if (s->sig == sig) {
|
||||||
|
assert(s->callback);
|
||||||
|
s->callback(a, s, sig, s->userdata);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int pa_signal_init(struct pa_mainloop_api *a) {
|
int pa_signal_init(struct pa_mainloop_api *a) {
|
||||||
|
|
@ -108,7 +106,8 @@ void pa_signal_done(void) {
|
||||||
while (signals)
|
while (signals)
|
||||||
pa_signal_free(signals);
|
pa_signal_free(signals);
|
||||||
|
|
||||||
api->io_free(io_event);
|
|
||||||
|
api->io_free(io_event);
|
||||||
io_event = NULL;
|
io_event = NULL;
|
||||||
|
|
||||||
close(signal_pipe[0]);
|
close(signal_pipe[0]);
|
||||||
|
|
|
||||||
|
|
@ -119,3 +119,14 @@ double pa_volume_to_dB(pa_volume_t v) {
|
||||||
|
|
||||||
return 20*log10((double) v/PA_VOLUME_NORM);
|
return 20*log10((double) v/PA_VOLUME_NORM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pa_bytes_snprint(char *s, size_t l, off_t v) {
|
||||||
|
if (v >= 1024*1024*1024)
|
||||||
|
snprintf(s, l, "%0.1f GB", (double) v/1024/1024/1024);
|
||||||
|
else if (v >= 1024*1024)
|
||||||
|
snprintf(s, l, "%0.1f MB", (double) v/1024/1024);
|
||||||
|
else if (v >= 1024)
|
||||||
|
snprintf(s, l, "%0.1f KB", (double) v/1024);
|
||||||
|
else
|
||||||
|
snprintf(s, l, "%u B", (unsigned) v);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,9 @@ double pa_volume_to_dB(pa_volume_t v);
|
||||||
#define PA_DECIBEL_MININFTY (-200)
|
#define PA_DECIBEL_MININFTY (-200)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Pretty print a byte size value. (i.e. "2.5 MB") */
|
||||||
|
void pa_bytes_snprint(char *s, size_t l, off_t v);
|
||||||
|
|
||||||
PA_C_DECL_END
|
PA_C_DECL_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
17
polyp/util.c
17
polyp/util.c
|
|
@ -223,16 +223,23 @@ void pa_raise_priority(void) {
|
||||||
fprintf(stderr, __FILE__": setpriority() failed: %s\n", strerror(errno));
|
fprintf(stderr, __FILE__": setpriority() failed: %s\n", strerror(errno));
|
||||||
else
|
else
|
||||||
fprintf(stderr, __FILE__": Successfully gained nice level %i.\n", NICE_LEVEL);
|
fprintf(stderr, __FILE__": Successfully gained nice level %i.\n", NICE_LEVEL);
|
||||||
|
|
||||||
#ifdef _POSIX_PRIORITY_SCHEDULING
|
#ifdef _POSIX_PRIORITY_SCHEDULING
|
||||||
{
|
{
|
||||||
struct sched_param sp;
|
struct sched_param sp;
|
||||||
sched_getparam(0, &sp);
|
|
||||||
|
if (sched_getparam(0, &sp) < 0) {
|
||||||
|
fprintf(stderr, __FILE__": sched_getparam() failed: %s\n", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sp.sched_priority = 1;
|
sp.sched_priority = 1;
|
||||||
if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0)
|
if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) {
|
||||||
fprintf(stderr, __FILE__": sched_setscheduler() failed: %s\n", strerror(errno));
|
fprintf(stderr, __FILE__": sched_setscheduler() failed: %s\n", strerror(errno));
|
||||||
else
|
return;
|
||||||
fprintf(stderr, __FILE__": Successfully gained SCHED_FIFO scheduling.\n");
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, __FILE__": Successfully enabled SCHED_FIFO scheduling.\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue