use signal instead of sleep while waiting at the end v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 04 Oct 2020 20:42:51 +0200
branchv_0
changeset 19 dcd98589f4b8
parent 18 7a74e9f9e674
child 20 ccc4e509c1f0
use signal instead of sleep while waiting at the end
src/CMakeLists.txt
src/JackHandler.h
--- a/src/CMakeLists.txt	Sun Oct 04 19:59:03 2020 +0200
+++ b/src/CMakeLists.txt	Sun Oct 04 20:42:51 2020 +0200
@@ -34,7 +34,7 @@
 )
 
 # Link libraries:
-target_link_libraries(${EXECUTABLE_FILE} ${RELPIPE_LIBS_LIBRARIES})
+target_link_libraries(${EXECUTABLE_FILE} ${RELPIPE_LIBS_LIBRARIES} pthread)
 set_property(TARGET ${EXECUTABLE_FILE} PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
 
 install(TARGETS ${EXECUTABLE_FILE} DESTINATION bin)
--- a/src/JackHandler.h	Sun Oct 04 19:59:03 2020 +0200
+++ b/src/JackHandler.h	Sun Oct 04 20:42:51 2020 +0200
@@ -28,6 +28,7 @@
 #include <sys/mman.h>
 #include <signal.h>
 #include <unistd.h>
+#include <pthread.h>
 
 #include <jack/jack.h>
 #include <jack/midiport.h>
@@ -73,6 +74,9 @@
 		jack_port_t* jackPort = nullptr;
 		jack_ringbuffer_t* ringBuffer = nullptr;
 
+		pthread_mutex_t processingLock = PTHREAD_MUTEX_INITIALIZER;
+		pthread_cond_t processingDone = PTHREAD_COND_INITIALIZER;
+
 		const int RING_BUFFER_SIZE = 100;
 
 		int processCallback(jack_nframes_t frames) {
@@ -86,11 +90,16 @@
 				jack_midi_data_t* midiData = jack_midi_event_reserve(jackPortBuffer, m.time, m.size);
 				memcpy(midiData, m.buffer, m.size);
 			}
+
+			if (pthread_mutex_trylock(&processingLock) == 0) {
+				pthread_cond_signal(&processingDone);
+				pthread_mutex_unlock(&processingLock);
+			}
+
 			return 0;
 		}
 
 		int syncCallback(jack_transport_state_t state, jack_position_t* position) {
-			std::wcerr << L"syncCallback()" << std::endl;
 			return true;
 		}
 
@@ -160,6 +169,7 @@
 		jack_deactivate(realTimeContext.jackClient);
 		jack_client_close(realTimeContext.jackClient);
 		jack_ringbuffer_free(realTimeContext.ringBuffer);
+		pthread_mutex_unlock(&realTimeContext.processingLock);
 	}
 
 	void failInConstructor(const relpipe::common::type::StringX& errorMessage) {
@@ -170,6 +180,8 @@
 public:
 
 	JackHandler(Configuration& configuration) : configuration(configuration) {
+		pthread_mutex_unlock(&realTimeContext.processingLock);
+
 		// Initialize JACK connection:
 		std::string clientName = convertor.to_bytes(configuration.jackClientName);
 		realTimeContext.jackClient = jack_client_open(clientName.c_str(), JackNullOption, nullptr);
@@ -284,11 +296,10 @@
 	}
 
 	void endOfPipe() {
-		// Wait until the ring buffer is empty
-		while (continueProcessing && jack_ringbuffer_read_space(realTimeContext.ringBuffer)) usleep(1000);
-		usleep(1000000);
-		// TODO: better waiting (ringBuffer might be empty, but events have not been sent to JACK yet)
 		// TODO: optionally mute all; probably enabled by default
+
+		// Wait until the ring buffer is empty (messages dequeued from the buffer) and real-time cycle was finished (messages passed to JACK)
+		while (continueProcessing && jack_ringbuffer_read_space(realTimeContext.ringBuffer)) pthread_cond_wait(&realTimeContext.processingDone, &realTimeContext.processingLock);
 	}
 
 	void finish(int sig) {