summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <Klaus (dot) Schmidinger (at) tvdr (dot) de>2017-06-04 09:47:20 (GMT)
committerManuel Reimer <manuel.reimer@gmx.de>2018-03-26 15:35:27 (GMT)
commit364d75c73a2ffd303a8f8e3ef3f537aecb1742ed (patch)
treee420a6e94fa84eba79bcd1a7fd26e14ca50b63e8
parente59728f4f77af1ef0cb4a2376b33a5e1d82e2e92 (diff)
downloadvdr-364d75c73a2ffd303a8f8e3ef3f537aecb1742ed.tar.gz
vdr-364d75c73a2ffd303a8f8e3ef3f537aecb1742ed.tar.bz2
Version 2.3.6vdr-2.3.6
VDR developer version 2.3.6 is now available at ftp://ftp.tvdr.de/vdr/Developer/vdr-2.3.6.tar.bz2 A 'diff' against the previous version is available at ftp://ftp.tvdr.de/vdr/Developer/vdr-2.3.5-2.3.6.diff MD5 checksums: eab982df03da492a7d263718a8c487c2 vdr-2.3.6.tar.bz2 84a53afa495740bfdf9aab4b8900df99 vdr-2.3.5-2.3.6.diff WARNING: ======== This is a *developer* version. Even though *I* use it in my productive environment, I strongly recommend that you only use it under controlled conditions and for testing and debugging. The changes since version 2.3.5: - Added backtrace functions for debugging (see cBackTrace in thread.h). - Added checking the correct sequence of locking global lists (with help and suggestions from Jasmin Jessich). At the first occurrence of an invalid locking sequence, the 20 most recent locks will be written to the log file, followed by a backtrace that led to the call in question. This code can be activated by defining the macro DEBUG_LOCKSEQ in thread.c (which is on by default). When debugging an actual invalid locking sequence, you can additionally define the macro DEBUG_LOCKCALL in thread.c, which will add information about the caller of each lock. Note that this may cause some stress on the CPU, therefore it is off by default. - The file Make.config.template now reacts on DEBUG=1 in the 'make' command line, and disables code optimizations by setting -O0 (thanks to Jasmin Jessich). This can be helpful when backtracing highly optimized code. You may want to 'make distclean' before running 'make' with a modified setting of DEBUG, to make sure all object files are newly compiled. - Fixed the locking sequence when dumping EPG data. - Fixed the locking sequence when starting a recording. - The Makefiles now use the macro $(Q) instead of a plain '@' in front of their commands, so that verbosity can be controlled by the user (suggested by Jasmin Jessich). Add VERBOSE=1 to the 'make' call in the VDR source directory to see the actual commands that are executed. Plugin authors should modify their makefiles accordingly, by simply preceeding the respective commands with '$(Q)' and inserting '@echo XX $@' (where XX is one of the character combinations listed in the release note for version 2.3.5) before the command. The newplugin script has also been modified accordingly. Note that if you build a plugin directly in the plugin's own source directory, the $(Q) macro won't be defined and commands will be displayed. You can add Q=@ to the make call to have it less verbose (provided the plugin's Makefile was modified as described above). - Added clearing CiResourceHandlers before shutting down the plugin manager. - Fixed a double channel switch when pressing the Channel+/- keys while no menu or channel display is open. - Fixed generating k_Release key events for LIRC remote controls (due to the short timeout another normal key was sometimes put into the queue after the generated release). Also removed some code redundancy and added some buffer checks. - Now using a separate mutex to fix the race between SVDRP CHAN and cDevice::HasProgramme(), because the previous fix caused a deadlock (reported by Derek Kelly). - Fixed a possible crash in case the SVDRP connection to a peer VDR is terminated while getting remote timers. - Fixed the locking sequence when creating a new timer from the Schedules menu. - Fixed the locking sequence when switching between 'Now', 'Next' and 'Schedule' in the Schedules menu.
-rw-r--r--CONTRIBUTORS7
-rw-r--r--HISTORY47
-rw-r--r--Make.config.template8
-rw-r--r--Makefile23
-rw-r--r--PLUGINS/src/epgtableid0/Makefile6
-rw-r--r--PLUGINS/src/hello/Makefile12
-rw-r--r--PLUGINS/src/osddemo/Makefile6
-rw-r--r--PLUGINS/src/pictures/Makefile12
-rw-r--r--PLUGINS/src/servicedemo/Makefile8
-rw-r--r--PLUGINS/src/skincurses/Makefile12
-rw-r--r--PLUGINS/src/status/Makefile6
-rw-r--r--PLUGINS/src/svdrpdemo/Makefile6
-rw-r--r--channels.c4
-rw-r--r--config.h10
-rw-r--r--device.c6
-rw-r--r--device.h3
-rw-r--r--epg.c10
-rw-r--r--epg.h4
-rw-r--r--libsi/Makefile4
-rw-r--r--lirc.c21
-rw-r--r--menu.c57
-rwxr-xr-xnewplugin12
-rw-r--r--recording.c4
-rw-r--r--svdrp.c10
-rw-r--r--thread.c271
-rw-r--r--thread.h33
-rw-r--r--timers.c4
-rw-r--r--vdr.c7
28 files changed, 489 insertions, 124 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 140ae53..6e228af 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -2858,6 +2858,8 @@ Derek Kelly <user.vdr@gmail.com>
for suggesting to change the naming of "binary skip mode" to "adaptive skip mode"
for suggesting to make the -u option also accept a numerical user id
for reporting a problem with abs() in gcc6+ when called with an unsigned variable
+ for reporting a deadlock after the fix for a race between SVDRP CHAN and
+ cDevice::HasProgramme()
Marcel Unbehaun <frostworks@gmx.de>
for adding cRecordingInfo::GetEvent()
@@ -3424,6 +3426,11 @@ Jasmin Jessich <jasmin@anw.at>
debugging MTD support
for fixing selecting delivery system names in case of undefined indexes
for fixing detecting the inclusion of STL header files in tools.h
+ for help and suggestions when implementing debug output for checking the correct
+ sequence of locking global lists
+ for suggesting to use $(Q) to control Makefile verbosity
+ for adding handling DEBUG to the Make.config.template file, in order to control
+ code optimization
Martin Schirrmacher <schirrmie@gmail.com>
for suggesting to provide a way for skin plugins to get informed about the currently
diff --git a/HISTORY b/HISTORY
index 7ce6586..32876ee 100644
--- a/HISTORY
+++ b/HISTORY
@@ -9055,3 +9055,50 @@ Video Disk Recorder Revision History
The newplugin script has also been modified accordingly.
- Fixed detecting the inclusion of STL header files in tools.h (thanks to Jasmin
Jessich).
+
+2017-06-04: Version 2.3.6
+
+- Added backtrace functions for debugging (see cBackTrace in thread.h).
+- Added checking the correct sequence of locking global lists (with help and
+ suggestions from Jasmin Jessich). At the first occurrence of an invalid locking
+ sequence, the 20 most recent locks will be written to the log file, followed by a
+ backtrace that led to the call in question. This code can be activated by defining
+ the macro DEBUG_LOCKSEQ in thread.c (which is on by default).
+ When debugging an actual invalid locking sequence, you can additionally define
+ the macro DEBUG_LOCKCALL in thread.c, which will add information about the caller
+ of each lock. Note that this may cause some stress on the CPU, therefore it is off
+ by default.
+- The file Make.config.template now reacts on DEBUG=1 in the 'make' command line,
+ and disables code optimizations by setting -O0 (thanks to Jasmin Jessich).
+ This can be helpful when backtracing highly optimized code. You may want to
+ 'make distclean' before running 'make' with a modified setting of DEBUG, to make
+ sure all object files are newly compiled.
+- Fixed the locking sequence when dumping EPG data.
+- Fixed the locking sequence when starting a recording.
+- The Makefiles now use the macro $(Q) instead of a plain '@' in front of their
+ commands, so that verbosity can be controlled by the user (suggested by Jasmin
+ Jessich). Add VERBOSE=1 to the 'make' call in the VDR source directory to see the
+ actual commands that are executed.
+ Plugin authors should modify their makefiles accordingly, by simply preceeding
+ the respective commands with '$(Q)' and inserting '@echo XX $@' (where XX is one
+ of the character combinations listed in the release note for version 2.3.5) before
+ the command.
+ The newplugin script has also been modified accordingly.
+ Note that if you build a plugin directly in the plugin's own source directory,
+ the $(Q) macro won't be defined and commands will be displayed. You can add
+ Q=@ to the make call to have it less verbose (provided the plugin's Makefile
+ was modified as described above).
+- Added clearing CiResourceHandlers before shutting down the plugin manager.
+- Fixed a double channel switch when pressing the Channel+/- keys while no menu
+ or channel display is open.
+- Fixed generating k_Release key events for LIRC remote controls (due to the short
+ timeout another normal key was sometimes put into the queue after the generated
+ release). Also removed some code redundancy and added some buffer checks.
+- Now using a separate mutex to fix the race between SVDRP CHAN and
+ cDevice::HasProgramme(), because the previous fix caused a deadlock (reported by
+ Derek Kelly).
+- Fixed a possible crash in case the SVDRP connection to a peer VDR is terminated
+ while getting remote timers.
+- Fixed the locking sequence when creating a new timer from the Schedules menu.
+- Fixed the locking sequence when switching between 'Now', 'Next' and 'Schedule'
+ in the Schedules menu.
diff --git a/Make.config.template b/Make.config.template
index 4b4317d..82d5561 100644
--- a/Make.config.template
+++ b/Make.config.template
@@ -6,7 +6,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: Make.config.template 4.0 2015/02/09 09:58:45 kls Exp $
+# $Id: Make.config.template 4.1 2017/06/02 09:29:54 kls Exp $
### The C compiler and options:
@@ -16,6 +16,12 @@ CFLAGS = -g -O3 -Wall
CXX = g++
CXXFLAGS = -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses
+# Use 'make DEBUG=1 ...' to build a debug version of VDR and plugins:
+ifdef DEBUG
+CFLAGS += -O0
+CXXFLAGS += -O0
+endif
+
# Use 'make M32=1 ...' to build a 32-bit version of VDR on a 64-bit machine:
ifdef M32
CFLAGS += -m32
diff --git a/Makefile b/Makefile
index 5b95dd0..a13214a 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: Makefile 4.4 2017/05/22 15:33:30 kls Exp $
+# $Id: Makefile 4.5 2017/05/29 08:48:42 kls Exp $
.DELETE_ON_ERROR:
@@ -52,6 +52,15 @@ DOXYFILE = Doxyfile
-include Make.config
+# Output control
+
+ifdef VERBOSE
+Q =
+else
+Q = @
+endif
+export Q
+
# Mandatory compiler flags:
CFLAGS += -fPIC
@@ -122,7 +131,7 @@ all: vdr i18n plugins
%.o: %.c
@echo CC $@
- @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ $(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
# Dependencies:
@@ -137,7 +146,7 @@ $(DEPFILE): Makefile
vdr: $(OBJS) $(SILIB)
@echo LD $@
- @$(CXX) $(CXXFLAGS) -rdynamic $(LDFLAGS) $(OBJS) $(LIBS) $(SILIB) -o vdr
+ $(Q)$(CXX) $(CXXFLAGS) -rdynamic $(LDFLAGS) $(OBJS) $(LIBS) $(SILIB) -o vdr
# The libsi library:
@@ -180,20 +189,20 @@ I18Npot = $(PODIR)/vdr.pot
%.mo: %.po
@echo MO $@
- @msgfmt -c -o $@ $<
+ $(Q)msgfmt -c -o $@ $<
$(I18Npot): $(wildcard *.c)
@echo GT $@
- @xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=VDR --package-version=$(VDRVERSION) --msgid-bugs-address='<vdr-bugs@tvdr.de>' -o $@ `ls $^`
+ $(Q)xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=VDR --package-version=$(VDRVERSION) --msgid-bugs-address='<vdr-bugs@tvdr.de>' -o $@ `ls $^`
%.po: $(I18Npot)
@echo PO $@
- @msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+ $(Q)msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@
$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr.mo: $(PODIR)/%.mo
@echo IN $@
- @install -D -m644 $< $@
+ $(Q)install -D -m644 $< $@
.PHONY: i18n
i18n: $(I18Nmsgs)
diff --git a/PLUGINS/src/epgtableid0/Makefile b/PLUGINS/src/epgtableid0/Makefile
index 5afb680..ef7cc71 100644
--- a/PLUGINS/src/epgtableid0/Makefile
+++ b/PLUGINS/src/epgtableid0/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.1 2017/05/22 15:30:42 kls Exp $
+# $Id: Makefile 4.2 2017/05/29 08:30:00 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -62,7 +62,7 @@ all: $(SOFILE)
%.o: %.c
@echo CC $@
- @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ $(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -77,7 +77,7 @@ $(DEPFILE): Makefile
$(SOFILE): $(OBJS)
@echo LD $@
- @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/hello/Makefile b/PLUGINS/src/hello/Makefile
index 79dcf22..5581c78 100644
--- a/PLUGINS/src/hello/Makefile
+++ b/PLUGINS/src/hello/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.1 2017/05/22 15:32:10 kls Exp $
+# $Id: Makefile 4.2 2017/05/29 08:26:45 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -63,7 +63,7 @@ all: $(SOFILE) i18n
%.o: %.c
@echo CC $@
- @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ $(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -84,15 +84,15 @@ I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
@echo MO $@
- @msgfmt -c -o $@ $<
+ $(Q)msgfmt -c -o $@ $<
$(I18Npot): $(wildcard *.c)
@echo GT $@
- @xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
+ $(Q)xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
%.po: $(I18Npot)
@echo PO $@
- @msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+ $(Q)msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
@@ -107,7 +107,7 @@ install-i18n: $(I18Nmsgs)
$(SOFILE): $(OBJS)
@echo LD $@
- @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/osddemo/Makefile b/PLUGINS/src/osddemo/Makefile
index 8750016..8deef83 100644
--- a/PLUGINS/src/osddemo/Makefile
+++ b/PLUGINS/src/osddemo/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.1 2017/05/22 15:30:47 kls Exp $
+# $Id: Makefile 4.2 2017/05/29 08:30:08 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -62,7 +62,7 @@ all: $(SOFILE)
%.o: %.c
@echo CC $@
- @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ $(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -77,7 +77,7 @@ $(DEPFILE): Makefile
$(SOFILE): $(OBJS)
@echo LD $@
- @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/pictures/Makefile b/PLUGINS/src/pictures/Makefile
index acb1f8e..1af0fff 100644
--- a/PLUGINS/src/pictures/Makefile
+++ b/PLUGINS/src/pictures/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.1 2017/05/22 15:31:28 kls Exp $
+# $Id: Makefile 4.2 2017/05/29 08:30:55 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -63,7 +63,7 @@ all: $(SOFILE) i18n
%.o: %.c
@echo CC $@
- @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ $(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -84,15 +84,15 @@ I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
@echo MO $@
- @msgfmt -c -o $@ $<
+ $(Q)msgfmt -c -o $@ $<
$(I18Npot): $(wildcard *.c)
@echo GT $@
- @xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
+ $(Q)xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
%.po: $(I18Npot)
@echo PO $@
- @msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+ $(Q)msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
@@ -107,7 +107,7 @@ install-i18n: $(I18Nmsgs)
$(SOFILE): $(OBJS)
@echo LD $@
- @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/servicedemo/Makefile b/PLUGINS/src/servicedemo/Makefile
index 074df3d..bb8fb19 100644
--- a/PLUGINS/src/servicedemo/Makefile
+++ b/PLUGINS/src/servicedemo/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.1 2017/05/22 15:31:59 kls Exp $
+# $Id: Makefile 4.2 2017/05/29 08:31:07 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -59,7 +59,7 @@ all: libvdr-$(PLUGIN1).so libvdr-$(PLUGIN2).so
%.o: %.c
@echo CC $@
- @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ $(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -74,11 +74,11 @@ $(DEPFILE): Makefile
libvdr-$(PLUGIN1).so: $(PLUGIN1).o
@echo LD $@
- @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(PLUGIN1).o -o $@
+ $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(PLUGIN1).o -o $@
libvdr-$(PLUGIN2).so: $(PLUGIN2).o
@echo LD $@
- @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(PLUGIN2).o -o $@
+ $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(PLUGIN2).o -o $@
install-lib: libvdr-$(PLUGIN1).so libvdr-$(PLUGIN2).so
install -D libvdr-$(PLUGIN1).so $(DESTDIR)$(LIBDIR)/libvdr-$(PLUGIN1).so.$(APIVERSION)
diff --git a/PLUGINS/src/skincurses/Makefile b/PLUGINS/src/skincurses/Makefile
index a1e05e5..5d591fd 100644
--- a/PLUGINS/src/skincurses/Makefile
+++ b/PLUGINS/src/skincurses/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.1 2017/05/22 15:31:47 kls Exp $
+# $Id: Makefile 4.2 2017/05/29 08:31:02 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -63,7 +63,7 @@ all: $(SOFILE) i18n
%.o: %.c
@echo CC $@
- @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ $(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -84,15 +84,15 @@ I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
@echo MO $@
- @msgfmt -c -o $@ $<
+ $(Q)msgfmt -c -o $@ $<
$(I18Npot): $(wildcard *.c)
@echo GT $@
- @xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
+ $(Q)xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
%.po: $(I18Npot)
@echo PO $@
- @msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+ $(Q)msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
@@ -107,7 +107,7 @@ install-i18n: $(I18Nmsgs)
$(SOFILE): $(OBJS)
@echo LD $@
- @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -lncursesw -o $@
+ $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -lncursesw -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/status/Makefile b/PLUGINS/src/status/Makefile
index bf5c80b..a97c509 100644
--- a/PLUGINS/src/status/Makefile
+++ b/PLUGINS/src/status/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.1 2017/05/22 15:30:58 kls Exp $
+# $Id: Makefile 4.2 2017/05/29 08:30:32 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -62,7 +62,7 @@ all: $(SOFILE)
%.o: %.c
@echo CC $@
- @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ $(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -77,7 +77,7 @@ $(DEPFILE): Makefile
$(SOFILE): $(OBJS)
@echo LD $@
- @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/svdrpdemo/Makefile b/PLUGINS/src/svdrpdemo/Makefile
index 292b8c7..ed378cd 100644
--- a/PLUGINS/src/svdrpdemo/Makefile
+++ b/PLUGINS/src/svdrpdemo/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.1 2017/05/22 15:31:19 kls Exp $
+# $Id: Makefile 4.2 2017/05/29 08:30:42 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -62,7 +62,7 @@ all: $(SOFILE)
%.o: %.c
@echo CC $@
- @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ $(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -77,7 +77,7 @@ $(DEPFILE): Makefile
$(SOFILE): $(OBJS)
@echo LD $@
- @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/channels.c b/channels.c
index 24fec5b..1b9aa86 100644
--- a/channels.c
+++ b/channels.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: channels.c 4.3 2015/09/09 10:21:22 kls Exp $
+ * $Id: channels.c 4.4 2017/05/26 15:43:54 kls Exp $
*/
#include "channels.h"
@@ -833,7 +833,7 @@ int cChannels::maxChannelNameLength = 0;
int cChannels::maxShortChannelNameLength = 0;
cChannels::cChannels(void)
-:cConfig<cChannel>("Channels")
+:cConfig<cChannel>("2 Channels")
{
modifiedByUser = 0;
}
diff --git a/config.h b/config.h
index c67b990..1b6e996 100644
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.h 4.9 2017/04/29 13:33:13 kls Exp $
+ * $Id: config.h 4.10 2017/05/28 12:42:49 kls Exp $
*/
#ifndef __CONFIG_H
@@ -22,13 +22,13 @@
// VDR's own version number:
-#define VDRVERSION "2.3.5"
-#define VDRVERSNUM 20305 // Version * 10000 + Major * 100 + Minor
+#define VDRVERSION "2.3.6"
+#define VDRVERSNUM 20306 // Version * 10000 + Major * 100 + Minor
// The plugin API's version number:
-#define APIVERSION "2.3.5"
-#define APIVERSNUM 20305 // Version * 10000 + Major * 100 + Minor
+#define APIVERSION "2.3.6"
+#define APIVERSNUM 20306 // Version * 10000 + Major * 100 + Minor
// When loading plugins, VDR searches them by their APIVERSION, which
// may be smaller than VDRVERSION in case there have been no changes to
diff --git a/device.c b/device.c
index 7c1c74b..3c67692 100644
--- a/device.c
+++ b/device.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.c 4.22 2017/05/18 09:27:55 kls Exp $
+ * $Id: device.c 4.23 2017/05/30 11:06:11 kls Exp $
*/
#include "device.h"
@@ -834,7 +834,7 @@ bool cDevice::SwitchChannel(int Direction)
eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
{
- cMutexLock MutexLock(&mutexReceiver); // to avoid a race between SVDRP CHAN and HasProgramme()
+ cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN and HasProgramme()
cStatus::MsgChannelSwitch(this, 0, LiveView);
if (LiveView) {
@@ -947,7 +947,7 @@ bool cDevice::HasLock(int TimeoutMs) const
bool cDevice::HasProgramme(void) const
{
- cMutexLock MutexLock(&mutexReceiver); // to avoid a race between SVDRP CHAN and HasProgramme()
+ cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN and HasProgramme()
return Replaying() || pidHandles[ptAudio].pid || pidHandles[ptVideo].pid;
}
diff --git a/device.h b/device.h
index f6aee4e..83e5178 100644
--- a/device.h
+++ b/device.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.h 4.9 2017/05/09 11:24:47 kls Exp $
+ * $Id: device.h 4.10 2017/05/30 11:06:11 kls Exp $
*/
#ifndef __DEVICE_H
@@ -257,6 +257,7 @@ public:
// Channel facilities
private:
+ mutable cMutex mutexChannel;
time_t occupiedTimeout;
protected:
static int currentChannel;
diff --git a/epg.c b/epg.c
index 7cbb011..486844e 100644
--- a/epg.c
+++ b/epg.c
@@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
*
- * $Id: epg.c 4.6 2017/05/09 12:16:36 kls Exp $
+ * $Id: epg.c 4.8 2017/05/28 13:08:09 kls Exp $
*/
#include "epg.h"
@@ -1104,9 +1104,8 @@ void cSchedule::Cleanup(time_t Time)
}
}
-void cSchedule::Dump(FILE *f, const char *Prefix, eDumpMode DumpMode, time_t AtTime) const
+void cSchedule::Dump(const cChannels *Channels, FILE *f, const char *Prefix, eDumpMode DumpMode, time_t AtTime) const
{
- LOCK_CHANNELS_READ;
if (const cChannel *Channel = Channels->GetByChannelID(channelID, true)) {
fprintf(f, "%sC %s %s\n", Prefix, *Channel->GetChannelID().ToString(), Channel->Name());
const cEvent *p;
@@ -1225,7 +1224,7 @@ char *cSchedules::epgDataFileName = NULL;
time_t cSchedules::lastDump = time(NULL);
cSchedules::cSchedules(void)
-:cList<cSchedule>("Schedules")
+:cList<cSchedule>("5 Schedules")
{
}
@@ -1280,9 +1279,10 @@ bool cSchedules::Dump(FILE *f, const char *Prefix, eDumpMode DumpMode, time_t At
return false;
}
}
+ LOCK_CHANNELS_READ;
LOCK_SCHEDULES_READ;
for (const cSchedule *p = Schedules->First(); p; p = Schedules->Next(p))
- p->Dump(f, Prefix, DumpMode, AtTime);
+ p->Dump(Channels, f, Prefix, DumpMode, AtTime);
if (sf) {
sf->Close();
delete sf;
diff --git a/epg.h b/epg.h
index fe536a7..6c42205 100644
--- a/epg.h
+++ b/epg.h
@@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
*
- * $Id: epg.h 4.6 2017/05/09 12:15:14 kls Exp $
+ * $Id: epg.h 4.7 2017/05/28 12:59:20 kls Exp $
*/
#ifndef __EPG_H
@@ -185,7 +185,7 @@ public:
const cEvent *GetFollowingEvent(void) const;
const cEvent *GetEvent(tEventID EventID, time_t StartTime = 0) const;
const cEvent *GetEventAround(time_t Time) const;
- void Dump(FILE *f, const char *Prefix = "", eDumpMode DumpMode = dmAll, time_t AtTime = 0) const;
+ void Dump(const cChannels *Channels, FILE *f, const char *Prefix = "", eDumpMode DumpMode = dmAll, time_t AtTime = 0) const;
static bool Read(FILE *f, cSchedules *Schedules);
};
diff --git a/libsi/Makefile b/libsi/Makefile
index 2ae223b..e0f9cb0 100644
--- a/libsi/Makefile
+++ b/libsi/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a libsi
#
-# $Id: Makefile 4.1 2017/05/22 15:33:20 kls Exp $
+# $Id: Makefile 4.2 2017/05/29 08:33:15 kls Exp $
### The archiver options:
@@ -37,7 +37,7 @@ all: libsi.a
libsi.a : $(OBJS)
@echo AR libsi/$@
- @$(AR) $(ARFLAGS) $@ $(OBJS)
+ $(Q)$(AR) $(ARFLAGS) $@ $(OBJS)
clean:
@-rm -f $(OBJS) $(DEPFILE) *.a *.so *.tgz core* *~
diff --git a/lirc.c b/lirc.c
index 526cd6d..d02ae11 100644
--- a/lirc.c
+++ b/lirc.c
@@ -6,7 +6,7 @@
*
* LIRC support added by Carsten Koch <Carsten.Koch@icem.de> 2000-06-16.
*
- * $Id: lirc.c 4.0 2013/10/29 12:32:12 kls Exp $
+ * $Id: lirc.c 4.1 2017/05/30 11:02:17 kls Exp $
*/
#include "lirc.h"
@@ -20,7 +20,7 @@ cLircRemote::cLircRemote(const char *DeviceName)
,cThread("LIRC remote control")
{
addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, DeviceName);
+ strn0cpy(addr.sun_path, DeviceName, sizeof(addr.sun_path));
if (!Connect())
f = -1;
Start();
@@ -94,12 +94,12 @@ void cLircRemote::Action(void)
}
int Delta = ThisTime.Elapsed(); // the time between two subsequent LIRC events
ThisTime.Set();
- if (count == 0) {
+ if (count == 0) { // new key pressed
if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < (uint)Setup.RcRepeatDelay)
continue; // skip keys coming in too fast
if (repeat)
- Put(LastKeyName, false, true);
- strcpy(LastKeyName, KeyName);
+ Put(LastKeyName, false, true); // generated release for previous repeated key
+ strn0cpy(LastKeyName, KeyName, sizeof(LastKeyName));
pressed = true;
repeat = false;
FirstTime.Set();
@@ -112,21 +112,16 @@ void cLircRemote::Action(void)
else {
pressed = true;
repeat = true;
- timeout = Delta * 10 / 9;
+ timeout = Delta * 3 / 2;
}
if (pressed) {
LastTime.Set();
Put(KeyName, repeat);
}
}
- else if (pressed && repeat) { // the last one was a repeat, so let's generate a release
- Put(LastKeyName, false, true);
- pressed = false;
- repeat = false;
- *LastKeyName = 0;
- timeout = -1;
- }
else {
+ if (pressed && repeat) // the last one was a repeat, so let's generate a release
+ Put(LastKeyName, false, true);
pressed = false;
repeat = false;
*LastKeyName = 0;
diff --git a/menu.c b/menu.c
index 246c4df..366390f 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 4.29 2017/05/21 13:18:26 kls Exp $
+ * $Id: menu.c 4.32 2017/06/04 09:30:56 kls Exp $
*/
#include "menu.h"
@@ -1550,7 +1550,7 @@ private:
static int currentChannel;
static const cEvent *scheduleEvent;
bool Update(void);
- void SetHelpKeys(void);
+ void SetHelpKeys(const cChannels *Channels);
public:
cMenuWhatsOn(const cTimers *Timers, const cChannels *Channels, const cSchedules *Schedules, bool Now, int CurrentChannelNr);
static int CurrentChannel(void) { return currentChannel; }
@@ -1579,7 +1579,7 @@ cMenuWhatsOn::cMenuWhatsOn(const cTimers *Timers, const cChannels *Channels, con
}
currentChannel = CurrentChannelNr;
Display();
- SetHelpKeys();
+ SetHelpKeys(Channels);
}
bool cMenuWhatsOn::Update(void)
@@ -1595,7 +1595,7 @@ bool cMenuWhatsOn::Update(void)
return result;
}
-void cMenuWhatsOn::SetHelpKeys(void)
+void cMenuWhatsOn::SetHelpKeys(const cChannels *Channels)
{
cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current());
canSwitch = false;
@@ -1609,7 +1609,6 @@ void cMenuWhatsOn::SetHelpKeys(void)
NewHelpKeys |= 0x04; // "Next"
else
NewHelpKeys |= 0x08; // "Now"
- LOCK_CHANNELS_READ;
if (const cChannel *Channel = Channels->GetByChannelID(item->event->ChannelID(), true)) {
if (Channel->Number() != cDevice::CurrentChannel()) {
NewHelpKeys |= 0x10; // "Switch"
@@ -1651,8 +1650,8 @@ eOSState cMenuWhatsOn::Switch(void)
eOSState cMenuWhatsOn::Record(void)
{
if (cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current())) {
- {
LOCK_TIMERS_WRITE;
+ LOCK_CHANNELS_READ;
LOCK_SCHEDULES_READ;
Timers->SetExplicitModify();
if (item->timerMatch == tmFull) {
@@ -1675,12 +1674,11 @@ eOSState cMenuWhatsOn::Record(void)
// must add the timer before HandleRemoteModifications to get proper log messages with timer ids
Timers->Del(Timer);
}
- }
if (HasSubMenu())
CloseSubMenu();
if (Update())
Display();
- SetHelpKeys();
+ SetHelpKeys(Channels);
}
return osContinue;
}
@@ -1715,7 +1713,8 @@ eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
if (((cMenuScheduleItem *)item)->channel->Number() == cDevice::CurrentChannel()) {
SetCurrent(item);
Display();
- SetHelpKeys();
+ LOCK_CHANNELS_READ;
+ SetHelpKeys(Channels);
break;
}
}
@@ -1734,8 +1733,10 @@ eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
else if (!HasSubMenu()) {
if (HadSubMenu && Update())
Display();
- if (Key != kNone)
- SetHelpKeys();
+ if (Key != kNone) {
+ LOCK_CHANNELS_READ;
+ SetHelpKeys(Channels);
+ }
}
return state;
}
@@ -1750,7 +1751,7 @@ private:
bool now, next;
bool canSwitch;
int helpKeys;
- void Set(const cChannel *Channel = NULL, bool Force = false);
+ void Set(const cTimers *Timers, const cChannels *Channels, const cChannel *Channel = NULL, bool Force = false);
eOSState Number(void);
eOSState Record(void);
eOSState Switch(void);
@@ -1776,7 +1777,9 @@ cMenuSchedule::cMenuSchedule(void)
helpKeys = 0;
cMenuScheduleItem::SetSortMode(cMenuScheduleItem::ssmAllThis);
cMenuWhatsOn::SetCurrentChannel(cDevice::CurrentChannel());
- Set(NULL, true);
+ LOCK_TIMERS_READ;
+ LOCK_CHANNELS_READ;
+ Set(Timers, Channels, NULL, true);
}
cMenuSchedule::~cMenuSchedule()
@@ -1784,14 +1787,12 @@ cMenuSchedule::~cMenuSchedule()
cMenuWhatsOn::ScheduleEvent(); // makes sure any posted data is cleared
}
-void cMenuSchedule::Set(const cChannel *Channel, bool Force)
+void cMenuSchedule::Set(const cTimers *Timers, const cChannels *Channels, const cChannel *Channel, bool Force)
{
if (Force) {
schedulesStateKey.Reset();
scheduleState = -1;
}
- LOCK_TIMERS_READ;
- LOCK_CHANNELS_READ;
if (const cSchedules *Schedules = cSchedules::GetSchedulesRead(schedulesStateKey)) {
cMenuScheduleItem *CurrentItem = (cMenuScheduleItem *)Get(Current());
const cEvent *Event = NULL;
@@ -1941,7 +1942,9 @@ void cMenuSchedule::SetHelpKeys(void)
eOSState cMenuSchedule::Number(void)
{
cMenuScheduleItem::IncSortMode();
- Set(NULL, true);
+ LOCK_TIMERS_READ;
+ LOCK_CHANNELS_READ;
+ Set(Timers, Channels, NULL, true);
return osContinue;
}
@@ -1950,6 +1953,7 @@ eOSState cMenuSchedule::Record(void)
if (cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current())) {
{
LOCK_TIMERS_WRITE;
+ LOCK_CHANNELS_READ;
LOCK_SCHEDULES_READ;
Timers->SetExplicitModify();
if (item->timerMatch == tmFull) {
@@ -2001,8 +2005,11 @@ eOSState cMenuSchedule::Switch(void)
eOSState cMenuSchedule::ProcessKey(eKeys Key)
{
- if (!HasSubMenu())
- Set(); // react on any changes to the schedules list
+ if (!HasSubMenu()) {
+ LOCK_TIMERS_READ;
+ LOCK_CHANNELS_READ;
+ Set(Timers, Channels); // react on any changes to the schedules list
+ }
bool HadSubMenu = HasSubMenu();
eOSState state = cOsdMenu::ProcessKey(Key);
@@ -2041,9 +2048,10 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
case kChanUp:
case kChanDn|k_Repeat:
case kChanDn: if (!HasSubMenu()) {
+ LOCK_TIMERS_READ;
LOCK_CHANNELS_READ;
if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel()))
- Set(Channel, true);
+ Set(Timers, Channels, Channel, true);
}
break;
case kInfo:
@@ -2060,10 +2068,11 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
else if (!HasSubMenu()) {
now = next = false;
if (const cEvent *ei = cMenuWhatsOn::ScheduleEvent()) {
+ LOCK_TIMERS_READ;
LOCK_CHANNELS_READ;
if (const cChannel *Channel = Channels->GetByChannelID(ei->ChannelID(), true)) {
cMenuScheduleItem::SetSortMode(cMenuScheduleItem::ssmAllThis);
- Set(Channel, true);
+ Set(Timers, Channels, Channel, true);
}
}
else if (HadSubMenu && Update())
@@ -5056,7 +5065,8 @@ cRecordControl::cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer,
Timers->SetModified();
// We're going to work with an event here, so we need to prevent
// others from modifying any EPG data:
- LOCK_SCHEDULES_READ;
+ cStateKey SchedulesStateKey;
+ cSchedules::GetSchedulesRead(SchedulesStateKey);
event = NULL;
fileName = NULL;
@@ -5092,6 +5102,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer,
cReplayControl::SetRecording(fileName);
}
timer = NULL;
+ SchedulesStateKey.Remove();
return;
}
@@ -5105,6 +5116,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer,
cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);
if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
cReplayControl::SetRecording(fileName);
+ SchedulesStateKey.Remove();
LOCK_RECORDINGS_WRITE;
Recordings->AddByName(fileName);
return;
@@ -5118,6 +5130,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer,
Timers->Del(timer);
timer = NULL;
}
+ SchedulesStateKey.Remove();
}
cRecordControl::~cRecordControl()
diff --git a/newplugin b/newplugin
index 161ffda..2e95393 100755
--- a/newplugin
+++ b/newplugin
@@ -12,7 +12,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: newplugin 4.2 2017/05/22 15:34:01 kls Exp $
+# $Id: newplugin 4.3 2017/05/29 08:55:21 kls Exp $
$PLUGIN_NAME = $ARGV[0] || die "Usage: newplugin <name>\n";
@@ -122,7 +122,7 @@ all: \$(SOFILE) i18n
%.o: %.c
\@echo CC \$\@
- \@\$(CXX) \$(CXXFLAGS) -c \$(DEFINES) \$(INCLUDES) -o \$\@ \$<
+ \$(Q)\$(CXX) \$(CXXFLAGS) -c \$(DEFINES) \$(INCLUDES) -o \$\@ \$<
### Dependencies:
@@ -143,15 +143,15 @@ I18Npot = \$(PODIR)/\$(PLUGIN).pot
%.mo: %.po
\@echo MO \$\@
- \@msgfmt -c -o \$\@ \$<
+ \$(Q)msgfmt -c -o \$\@ \$<
\$(I18Npot): \$(wildcard *.c)
\@echo GT \$\@
- \@xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-\$(PLUGIN) --package-version=\$(VERSION) --msgid-bugs-address='<see README>' -o \$\@ `ls \$^`
+ \$(Q)xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-\$(PLUGIN) --package-version=\$(VERSION) --msgid-bugs-address='<see README>' -o \$\@ `ls \$^`
%.po: \$(I18Npot)
\@echo PO \$\@
- \@msgmerge -U --no-wrap --no-location --backup=none -q -N \$\@ \$<
+ \$(Q)msgmerge -U --no-wrap --no-location --backup=none -q -N \$\@ \$<
\@touch \$\@
\$(I18Nmsgs): \$(DESTDIR)\$(LOCDIR)/%/LC_MESSAGES/vdr-\$(PLUGIN).mo: \$(PODIR)/%.mo
@@ -166,7 +166,7 @@ install-i18n: \$(I18Nmsgs)
\$(SOFILE): \$(OBJS)
\@echo LD \$\@
- \@\$(CXX) \$(CXXFLAGS) \$(LDFLAGS) -shared \$(OBJS) -o \$\@
+ \$(Q)\$(CXX) \$(CXXFLAGS) \$(LDFLAGS) -shared \$(OBJS) -o \$\@
install-lib: \$(SOFILE)
install -D \$^ \$(DESTDIR)\$(LIBDIR)/\$^.\$(APIVERSION)
diff --git a/recording.c b/recording.c
index 9f96b73..7b1d158 100644
--- a/recording.c
+++ b/recording.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recording.c 4.8 2017/04/03 13:34:30 kls Exp $
+ * $Id: recording.c 4.9 2017/05/27 15:46:57 kls Exp $
*/
#include "recording.h"
@@ -1469,7 +1469,7 @@ cVideoDirectoryScannerThread *cRecordings::videoDirectoryScannerThread = NULL;
time_t cRecordings::lastUpdate = 0;
cRecordings::cRecordings(bool Deleted)
-:cList<cRecording>(Deleted ? "DelRecs" : "Recordings")
+:cList<cRecording>(Deleted ? "4 DelRecs" : "3 Recordings")
{
}
diff --git a/svdrp.c b/svdrp.c
index f402c21..2b63c80 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
- * $Id: svdrp.c 4.18 2017/05/18 15:51:24 kls Exp $
+ * $Id: svdrp.c 4.20 2017/05/31 14:02:17 kls Exp $
*/
#include "svdrp.h"
@@ -385,7 +385,8 @@ void cSVDRPClient::Close(void)
file.Close();
socket.Close();
LOCK_TIMERS_WRITE;
- Timers->DelRemoteTimers(serverName);
+ if (Timers)
+ Timers->DelRemoteTimers(serverName);
}
}
@@ -463,6 +464,7 @@ bool cSVDRPClient::Process(cStringList *Response)
else if (r <= 0) {
isyslog("SVDRP < %s lost connection to remote server '%s'", ipAddress.Connection(), *serverName);
Close();
+ return false;
}
}
else if (!Response)
@@ -1615,6 +1617,7 @@ void cSVDRPServer::CmdLSTC(const char *Option)
void cSVDRPServer::CmdLSTE(const char *Option)
{
+ LOCK_CHANNELS_READ;
LOCK_SCHEDULES_READ;
const cSchedule* Schedule = NULL;
eDumpMode DumpMode = dmAll;
@@ -1646,7 +1649,6 @@ void cSVDRPServer::CmdLSTE(const char *Option)
}
}
else if (!Schedule) {
- LOCK_CHANNELS_READ;
const cChannel* Channel = NULL;
if (isnumber(p))
Channel = Channels->GetByNumber(strtol(Option, NULL, 10));
@@ -1676,7 +1678,7 @@ void cSVDRPServer::CmdLSTE(const char *Option)
FILE *f = fdopen(fd, "w");
if (f) {
if (Schedule)
- Schedule->Dump(f, "215-", DumpMode, AtTime);
+ Schedule->Dump(Channels, f, "215-", DumpMode, AtTime);
else
Schedules->Dump(f, "215-", DumpMode, AtTime);
fflush(f);
diff --git a/thread.c b/thread.c
index 47eb977..345f2af 100644
--- a/thread.c
+++ b/thread.c
@@ -4,26 +4,31 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: thread.c 4.2 2016/12/08 09:45:25 kls Exp $
+ * $Id: thread.c 4.4 2017/06/03 12:43:22 kls Exp $
*/
#include "thread.h"
+#include <cxxabi.h>
+#include <dlfcn.h>
#include <errno.h>
+#include <execinfo.h>
#include <linux/unistd.h>
#include <malloc.h>
#include <stdarg.h>
#include <stdlib.h>
+#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/wait.h>
-#include <sys/prctl.h>
#include <unistd.h>
#include "tools.h"
-#define ABORT { dsyslog("ABORT!"); abort(); } // use debugger to trace back the problem
+#define ABORT { dsyslog("ABORT!"); cBackTrace::BackTrace(); abort(); }
-//#define DEBUG_LOCKING // uncomment this line to activate debug output for locking
+//#define DEBUG_LOCKING // uncomment this line to activate debug output for locking
+#define DEBUG_LOCKSEQ // uncomment this line to activate debug output for invalid locking sequence
+//#define DEBUG_LOCKCALL // uncomment this line to activate caller information with DEBUG_LOCKSEQ (WARNING: expensive operation, use only when actually debugging the locking sequence!)
#ifdef DEBUG_LOCKING
#define dbglocking(a...) fprintf(stderr, a)
@@ -429,6 +434,249 @@ bool cThreadLock::Lock(cThread *Thread)
return false;
}
+// --- cBackTrace ------------------------------------------------------------
+
+#define BT_BUF_SIZE 100
+
+cString cBackTrace::Demangle(char *s)
+{
+ char *Module = s;
+ char *Function = NULL;
+ char *Offset = NULL;
+ char *Address = NULL;
+ // separate the string:
+ for (char *q = Module; *q; q++) {
+ if (*q == '(') {
+ *q = 0;
+ Function = q + 1;
+ }
+ else if (*q == '+') {
+ *q = 0;
+ Offset = q + 1;
+ }
+ else if (*q == ')')
+ *q = 0;
+ else if (*q == '[')
+ Address = q + 1;
+ else if (*q == ']') {
+ *q = 0;
+ break;
+ }
+ }
+ // demangle the function name:
+ char *DemangledFunction = NULL;
+ if (Function) {
+ int status;
+ DemangledFunction = abi::__cxa_demangle(Function, NULL, 0, &status);
+ if (DemangledFunction)
+ Function = DemangledFunction;
+ if (!*Function)
+ Function = NULL;
+ }
+ cString d = cString::sprintf("%s%s%s", Module, Function ? " " : "", Function ? Function : "");
+ // convert string address to numbers:
+ unsigned long long addr = Address ? strtoull(Address, NULL, 0) : 0;
+ unsigned long long offs = Offset ? strtoull(Offset, NULL, 0) : 0;
+ // for shared libraries we need get the offset inside the library:
+ if (Function) {
+ // check whether the module name ends with ".so*":
+ char *e = Module;
+ char *p = NULL;
+ while (e = strstr(e, ".so"))
+ p = e++;
+ if (p && !strchr(p, '/')) {
+ Dl_info dlinfo;
+ if (dladdr(reinterpret_cast<void*>(addr), &dlinfo)) {
+ if ((strcmp(Module, dlinfo.dli_fname) == 0) && dlinfo.dli_fbase) {
+ unsigned long long base = reinterpret_cast<unsigned long long>(dlinfo.dli_fbase);
+ addr -= base;
+ addr &= 0x0FFFFFFFF; // to make it work on both 32 and 64 bit systems
+ }
+ }
+ }
+ }
+ // determine the file name and line number:
+ cString cmd = cString::sprintf("addr2line --functions --demangle --inlines --basename --exe=%s 0x%llx", Module, Function ? addr : offs);
+ cPipe p;
+ if (p.Open(cmd, "r")) {
+ int n = 0;
+ cReadLine rl;
+ while (char *l = rl.Read(p)) {
+ if (n == 0) {
+ if (Function && strcmp(l, Function))
+ d = cString::sprintf("%s calling %s", *d, l);
+ }
+ else
+ d = cString::sprintf("%s at %s", *d, l);
+ n++;
+ }
+ p.Close();
+ }
+ free(DemangledFunction);
+ return d;
+}
+
+void cBackTrace::BackTrace(cStringList &StringList, int Level, bool Mangled)
+{
+ void *b[BT_BUF_SIZE];
+ int n = backtrace(b, BT_BUF_SIZE);
+ if (char **s = backtrace_symbols(b, n)) {
+ for (int i = max(Level, 0) + 1; i < n; i++) // 1 is the call to this function itself
+ StringList.Append(strdup(Mangled ? s[i] : *Demangle(s[i])));
+ free(s);
+ }
+}
+
+void cBackTrace::BackTrace(FILE *f, int Level, bool Mangled)
+{
+ cStringList sl;
+ BackTrace(sl, Level + 1, Mangled); // 1 is the call to this function itself
+ for (int i = 0; i < sl.Size(); i++) {
+ if (f)
+ fprintf(f, "%s\n", sl[i]);
+ else
+ dsyslog("%s", sl[i]);
+ }
+}
+
+cString cBackTrace::GetCaller(int Level, bool Mangled)
+{
+ cString Caller;
+ Level = max(Level, 0) + 1; // 1 is the call to this function itself
+ void *b[BT_BUF_SIZE];
+ int n = backtrace(b, BT_BUF_SIZE);
+ if (char **s = backtrace_symbols(b, n)) {
+ if (Level < n)
+ Caller = Mangled ? s[Level] : *Demangle(s[Level]);
+ free(s);
+ }
+ return Caller;
+}
+
+// --- cStateLockLog ---------------------------------------------------------
+
+#ifdef DEBUG_LOCKSEQ
+#define SLL_SIZE 20 // the number of log entries
+#define SLL_LENGTH 256 // the maximum length of log entries
+#define SLL_MAX_LIST 9 // max. number of lists to log
+#define SLL_WRITE_FLAG 0x80000000
+
+class cStateLockLog {
+private:
+ cMutex mutex;
+ cVector<tThreadId> threadIds;
+ cVector<int> flags;
+ tThreadId logThreadIds[SLL_SIZE];
+ int logFlags[SLL_SIZE];
+ char logCaller[SLL_SIZE][SLL_LENGTH];
+ int logIndex;
+ bool dumped;
+ void Dump(const char *Name, tThreadId ThreadId);
+public:
+ cStateLockLog(void);
+ void Check(const char *Name, bool Lock, bool Write = false);
+ };
+
+cStateLockLog::cStateLockLog(void)
+{
+ memset(logThreadIds, 0, sizeof(logThreadIds));
+ memset(logFlags, 0, sizeof(logFlags));
+ memset(logCaller, 0, sizeof(logCaller));
+ logIndex = 0;
+ dumped = false;
+}
+
+void cStateLockLog::Dump(const char *Name, tThreadId ThreadId)
+{
+ dsyslog("--- begin invalid lock sequence report");
+ int LastFlags = 0;
+ for (int i = 0; i < SLL_SIZE; i++) {
+ if (tThreadId tid = logThreadIds[logIndex]) {
+ char msg[SLL_LENGTH];
+ char *q = msg;
+ q += sprintf(q, "%5d", tid);
+ int Flags = logFlags[logIndex];
+ bool Write = Flags & SLL_WRITE_FLAG;
+ Flags &= ~SLL_WRITE_FLAG;
+ int Changed = LastFlags ^ Flags;
+ LastFlags = Flags;
+ bool Lock = (Flags & Changed) != 0;
+ for (int i = 0; i <= SLL_MAX_LIST; i++) {
+ char c = '-';
+ int b = 1 << i;
+ if ((Flags & b) != 0)
+ c = '*';
+ if ((Changed & b) != 0)
+ c = Lock ? Write ? 'W' : 'R' : '-';
+ q += sprintf(q, " %c", c);
+ }
+ q += sprintf(q, " %c", Lock ? 'L' : 'U');
+ if (*logCaller[logIndex]) {
+ *q++ = ' ';
+ strn0cpy(q, *cBackTrace::Demangle(logCaller[logIndex]), sizeof(msg) - (q - msg));
+ }
+ dsyslog("%s", msg);
+ }
+ if (++logIndex >= SLL_SIZE)
+ logIndex = 0;
+ }
+ dsyslog("%5d invalid lock sequence: %s", ThreadId, Name);
+ dsyslog("full backtrace:");
+ cBackTrace::BackTrace(NULL, 2);
+ dsyslog("--- end invalid lock sequence report");
+ fprintf(stderr, "invalid lock sequence at %s\n", *DayDateTime(time(NULL)));
+}
+
+void cStateLockLog::Check(const char *Name, bool Lock, bool Write)
+{
+ if (!dumped && Name) {
+ int n = *Name - '0';
+ if (1 <= n && n <= SLL_MAX_LIST) {
+ int b = 1 << (n - 1);
+ cMutexLock MutexLock(&mutex);
+ tThreadId ThreadId = cThread::ThreadId();
+ int Index = threadIds.IndexOf(ThreadId);
+ if (Index < 0) {
+ if (Lock) {
+ Index = threadIds.Size();
+ threadIds.Append(ThreadId);
+ flags.Append(0);
+ }
+ else
+ return;
+ }
+ bool DoDump = false;
+ if (Lock) {
+ if ((flags[Index] & ~b) < b) // thread holds only "smaller" locks -> OK
+ ;
+ else if ((flags[Index] & b) == 0) // thread already holds "bigger" locks, so it may only re-lock one that it already has!
+ DoDump = true;
+ flags[Index] |= b;
+ }
+ else
+ flags[Index] &= ~b;
+ logThreadIds[logIndex] = ThreadId;
+ logFlags[logIndex] = flags[Index] | (Write ? SLL_WRITE_FLAG : 0);
+#ifdef DEBUG_LOCKCALL
+ strn0cpy(logCaller[logIndex], cBackTrace::GetCaller(Lock ? 5 : 3, true), SLL_LENGTH);
+#endif
+ if (++logIndex >= SLL_SIZE)
+ logIndex = 0;
+ if (DoDump) {
+ Dump(Name, ThreadId);
+ dumped = true;
+ }
+ }
+ }
+}
+
+static cStateLockLog StateLockLog;
+
+#define dbglockseq(n, l, w) StateLockLog.Check(n, l, w)
+#else
+#define dbglockseq(n, l, w)
+#endif // DEBUG_LOCKSEQ
+
// --- cStateLock ------------------------------------------------------------
cStateLock::cStateLock(const char *Name)
@@ -442,7 +690,7 @@ cStateLock::cStateLock(const char *Name)
bool cStateLock::Lock(cStateKey &StateKey, bool Write, int TimeoutMs)
{
- dbglocking("%5d %-10s %10p lock state = %d/%d write = %d timeout = %d\n", cThread::ThreadId(), name, &StateKey, state, StateKey.state, Write, TimeoutMs);
+ dbglocking("%5d %-12s %10p lock state = %d/%d write = %d timeout = %d\n", cThread::ThreadId(), name, &StateKey, state, StateKey.state, Write, TimeoutMs);
StateKey.timedOut = false;
if (StateKey.stateLock) {
esyslog("ERROR: StateKey already in use in call to cStateLock::Lock() (tid=%d, lock=%s)", StateKey.stateLock->threadId, name);
@@ -450,25 +698,27 @@ bool cStateLock::Lock(cStateKey &StateKey, bool Write, int TimeoutMs)
return false;
}
if (rwLock.Lock(Write, TimeoutMs)) {
+ dbglockseq(name, true, Write);
StateKey.stateLock = this;
if (Write) {
- dbglocking("%5d %-10s %10p locked write\n", cThread::ThreadId(), name, &StateKey);
+ dbglocking("%5d %-12s %10p locked write\n", cThread::ThreadId(), name, &StateKey);
threadId = cThread::ThreadId();
StateKey.write = true;
return true;
}
else if (state != StateKey.state) {
- dbglocking("%5d %-10s %10p locked read\n", cThread::ThreadId(), name, &StateKey);
+ dbglocking("%5d %-12s %10p locked read\n", cThread::ThreadId(), name, &StateKey);
return true;
}
else {
- dbglocking("%5d %-10s %10p state unchanged\n", cThread::ThreadId(), name, &StateKey);
+ dbglocking("%5d %-12s %10p state unchanged\n", cThread::ThreadId(), name, &StateKey);
StateKey.stateLock = NULL;
+ dbglockseq(name, false, false);
rwLock.Unlock();
}
}
else if (TimeoutMs) {
- dbglocking("%5d %-10s %10p timeout\n", cThread::ThreadId(), name, &StateKey);
+ dbglocking("%5d %-12s %10p timeout\n", cThread::ThreadId(), name, &StateKey);
StateKey.timedOut = true;
}
return false;
@@ -476,7 +726,7 @@ bool cStateLock::Lock(cStateKey &StateKey, bool Write, int TimeoutMs)
void cStateLock::Unlock(cStateKey &StateKey, bool IncState)
{
- dbglocking("%5d %-10s %10p unlock state = %d/%d inc = %d\n", cThread::ThreadId(), name, &StateKey, state, StateKey.state, IncState);
+ dbglocking("%5d %-12s %10p unlock state = %d/%d inc = %d\n", cThread::ThreadId(), name, &StateKey, state, StateKey.state, IncState);
if (StateKey.stateLock != this) {
esyslog("ERROR: cStateLock::Unlock() called with an unused key (tid=%d, lock=%s)", threadId, name);
ABORT;
@@ -495,6 +745,7 @@ void cStateLock::Unlock(cStateKey &StateKey, bool IncState)
threadId = 0;
explicitModify = false;
}
+ dbglockseq(name, false, false);
rwLock.Unlock();
}
diff --git a/thread.h b/thread.h
index 8cca55c..33f90c7 100644
--- a/thread.h
+++ b/thread.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: thread.h 4.2 2016/12/08 09:11:24 kls Exp $
+ * $Id: thread.h 4.3 2017/05/31 11:39:11 kls Exp $
*/
#ifndef __THREAD_H
@@ -291,6 +291,37 @@ public:
int Close(void);
};
+// cBackTrace can be used for debugging.
+
+class cStringList;
+class cString;
+
+class cBackTrace {
+public:
+ static cString Demangle(char *s);
+ ///< Demangles the function name in the given string and returns the converted
+ ///< version of s. s must be one of the strings returned by a call to
+ ///< BackTrace() or GetCaller().
+ ///< Note that this function works on the given string by inserting '\0'
+ ///< characters to separate the individual parts. Therefore the string
+ ///< will be modified upon return.
+ static void BackTrace(cStringList &StringList, int Level = 0, bool Mangled = false);
+ ///< Produces a backtrace and stores it in the given StringList.
+ ///< If Level is given, only calls up to the given value are listed.
+ ///< If Mangled is true, the raw backtrace will be returned and you can use
+ ///< Demangle() to make the function names readable.
+ static void BackTrace(FILE *f = NULL, int Level = 0, bool Mangled = false);
+ ///< Produces a backtrace beginning at the given Level, and
+ ///< writes it to the given file. If no file is given, the backtrace is
+ ///< written to the logfile. If Mangled is true, the raw backtrace will
+ ///< be printed/logged.
+ static cString GetCaller(int Level = 0, bool Mangled = false);
+ ///< Returns the caller at the given Level (or the immediate caller,
+ ///< if Level is 0).
+ ///< If Mangled is true, the raw backtrace will be returned and you can use
+ ///< Demangle() to make the function name readable.
+ };
+
// SystemExec() implements a 'system()' call that closes all unnecessary file
// descriptors in the child process.
// With Detached=true, calls command in background and in a separate session,
diff --git a/timers.c b/timers.c
index 4cf8fb7..95cb723 100644
--- a/timers.c
+++ b/timers.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: timers.c 4.9 2017/04/20 09:15:06 kls Exp $
+ * $Id: timers.c 4.10 2017/05/26 15:43:38 kls Exp $
*/
#include "timers.h"
@@ -714,7 +714,7 @@ cTimers cTimers::timers;
int cTimers::lastTimerId = 0;
cTimers::cTimers(void)
-:cConfig<cTimer>("Timers")
+:cConfig<cTimer>("1 Timers")
{
lastDeleteExpired = 0;
}
diff --git a/vdr.c b/vdr.c
index 41dbc8f..4b42468 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.tvdr.de
*
- * $Id: vdr.c 4.14 2017/05/21 12:31:37 kls Exp $
+ * $Id: vdr.c 4.16 2017/05/29 11:30:27 kls Exp $
*/
#include <getopt.h>
@@ -1274,8 +1274,10 @@ int main(int argc, char *argv[])
case kChanUp:
case kChanDn|k_Repeat:
case kChanDn:
- if (!Interact)
+ if (!Interact) {
Menu = new cDisplayChannel(NORMALKEY(key));
+ continue;
+ }
else if (cDisplayChannel::IsOpen() || cControl::Control()) {
Interact->ProcessKey(key);
continue;
@@ -1585,6 +1587,7 @@ Exit:
cVideoDirectory::Destroy();
EpgHandlers.Clear();
cSchedules::Cleanup(true);
+ CiResourceHandlers.Clear();
ListGarbageCollector.Purge(true);
PluginManager.Shutdown(true);
ReportEpgBugFixStats(true);