| @@ -83,6 +83,7 @@ def build(bld): | |||||
| 'JackDebugClient.cpp', | 'JackDebugClient.cpp', | ||||
| 'timestamps.c', | 'timestamps.c', | ||||
| 'promiscuous.c', | 'promiscuous.c', | ||||
| '../posix/JackPosixCommon.cpp', | |||||
| '../posix/JackPosixThread.cpp', | '../posix/JackPosixThread.cpp', | ||||
| '../posix/JackPosixProcessSync.cpp', | '../posix/JackPosixProcessSync.cpp', | ||||
| '../posix/JackPosixMutex.cpp', | '../posix/JackPosixMutex.cpp', | ||||
| @@ -113,6 +114,7 @@ def build(bld): | |||||
| 'JackDebugClient.cpp', | 'JackDebugClient.cpp', | ||||
| 'timestamps.c', | 'timestamps.c', | ||||
| 'promiscuous.c', | 'promiscuous.c', | ||||
| '../posix/JackPosixCommon.cpp', | |||||
| '../posix/JackPosixThread.cpp', | '../posix/JackPosixThread.cpp', | ||||
| '../posix/JackFifo.cpp', | '../posix/JackFifo.cpp', | ||||
| '../posix/JackPosixProcessSync.cpp', | '../posix/JackPosixProcessSync.cpp', | ||||
| @@ -128,6 +130,7 @@ def build(bld): | |||||
| 'JackDebugClient.cpp', | 'JackDebugClient.cpp', | ||||
| 'timestamps.c', | 'timestamps.c', | ||||
| 'promiscuous.c', | 'promiscuous.c', | ||||
| '../posix/JackPosixCommon.cpp', | |||||
| '../posix/JackPosixProcessSync.cpp', | '../posix/JackPosixProcessSync.cpp', | ||||
| '../posix/JackPosixThread.cpp', | '../posix/JackPosixThread.cpp', | ||||
| '../posix/JackPosixMutex.cpp', | '../posix/JackPosixMutex.cpp', | ||||
| @@ -0,0 +1,50 @@ | |||||
| #include "JackPosixCommon.h" | |||||
| #include "JackConstants.h" | |||||
| #include "JackTools.h" | |||||
| #include "JackError.h" | |||||
| #include <assert.h> | |||||
| #include <time.h> | |||||
| #include <string.h> | |||||
| #include <stdio.h> | |||||
| #include <unistd.h> | |||||
| namespace Jack | |||||
| { | |||||
| void JackPosixTools::TimespecAdd(const struct timespec *left, | |||||
| const struct timespec *right, struct timespec *result) | |||||
| { | |||||
| assert(result != NULL); | |||||
| result->tv_sec = left->tv_sec + right->tv_sec; | |||||
| result->tv_nsec = left->tv_nsec + right->tv_nsec; | |||||
| if (result->tv_nsec >= 1000000000) { | |||||
| result->tv_nsec -= 1000000000; | |||||
| result->tv_sec += 1; | |||||
| } | |||||
| } | |||||
| void JackPosixTools::TimespecSub(const struct timespec *left, | |||||
| const struct timespec *right, struct timespec *result) | |||||
| { | |||||
| assert(result != NULL); | |||||
| result->tv_sec = left->tv_sec - right->tv_sec; | |||||
| result->tv_nsec = left->tv_nsec - right->tv_nsec; | |||||
| if (result->tv_nsec < 0) { | |||||
| result->tv_nsec += 1000000000; | |||||
| result->tv_sec -= 1; | |||||
| } | |||||
| } | |||||
| int JackPosixTools::TimespecCmp(const struct timespec *left, | |||||
| const struct timespec *right) | |||||
| { | |||||
| if (left->tv_sec != right->tv_sec) | |||||
| return left->tv_sec < right->tv_sec ? -1 : 1; | |||||
| if (left->tv_nsec != right->tv_nsec) | |||||
| return left->tv_nsec < right->tv_nsec ? -1 : 1; | |||||
| return 0; | |||||
| } | |||||
| } // end of namespace | |||||
| @@ -0,0 +1,30 @@ | |||||
| #ifndef __JackPosixCommon__ | |||||
| #define __JackPosixCommon__ | |||||
| #include "jslist.h" | |||||
| #include "JackCompilerDeps.h" | |||||
| #include "JackError.h" | |||||
| #include <errno.h> | |||||
| #include <time.h> | |||||
| #include <unistd.h> | |||||
| namespace Jack | |||||
| { | |||||
| struct SERVER_EXPORT JackPosixTools | |||||
| { | |||||
| static void TimespecAdd(const struct timespec *left, | |||||
| const struct timespec *right, struct timespec *result); | |||||
| static void TimespecSub(const struct timespec *left, | |||||
| const struct timespec *right, struct timespec *result); | |||||
| static int TimespecCmp(const struct timespec *left, | |||||
| const struct timespec *right); | |||||
| }; | |||||
| } // end of namespace | |||||
| #endif | |||||
| @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
| #include "JackPosixProcessSync.h" | #include "JackPosixProcessSync.h" | ||||
| #include "JackError.h" | #include "JackError.h" | ||||
| #include "JackPosixCommon.h" | |||||
| namespace Jack | namespace Jack | ||||
| { | { | ||||
| @@ -103,73 +104,94 @@ void JackPosixProcessSync::LockedWait() | |||||
| } | } | ||||
| } | } | ||||
| bool JackPosixProcessSync::TimedWait(long usec) | |||||
| { | |||||
| ThrowIf(!pthread_equal(pthread_self(), fOwner), JackException("JackPosixProcessSync::TimedWait: a thread has to have locked a mutex before it can wait")); | |||||
| fOwner = 0; | |||||
| struct timeval T0, T1; | |||||
| timespec time; | |||||
| struct timeval now; | |||||
| int res; | |||||
| jack_log("JackPosixProcessSync::TimedWait time out = %ld", usec); | |||||
| gettimeofday(&T0, 0); | |||||
| gettimeofday(&now, 0); | |||||
| unsigned int next_date_usec = now.tv_usec + usec; | |||||
| time.tv_sec = now.tv_sec + (next_date_usec / 1000000); | |||||
| time.tv_nsec = (next_date_usec % 1000000) * 1000; | |||||
| res = pthread_cond_timedwait(&fCond, &fMutex, &time); | |||||
| if (res != 0) { | |||||
| jack_error("JackPosixProcessSync::TimedWait error usec = %ld err = %s", usec, strerror(res)); | |||||
| } else { | |||||
| fOwner = pthread_self(); | |||||
| } | |||||
| gettimeofday(&T1, 0); | |||||
| jack_log("JackPosixProcessSync::TimedWait finished delta = %5.1lf", | |||||
| (1e6 * T1.tv_sec - 1e6 * T0.tv_sec + T1.tv_usec - T0.tv_usec)); | |||||
| return (res == 0); | |||||
| } | |||||
| // TO DO : check thread consistency? | // TO DO : check thread consistency? | ||||
| bool JackPosixProcessSync::LockedTimedWait(long usec) | bool JackPosixProcessSync::LockedTimedWait(long usec) | ||||
| { | { | ||||
| struct timeval T0, T1; | |||||
| timespec time; | |||||
| struct timeval now; | |||||
| int res1, res2; | |||||
| int res1, res2, res3; | |||||
| struct timespec rel_timeout, now_mono, end_mono, now_real, end_real; | |||||
| struct timespec diff_mono, final_time; | |||||
| int old_errno; | |||||
| bool mono_available = true; | |||||
| double delta; | |||||
| res1 = pthread_mutex_lock(&fMutex); | res1 = pthread_mutex_lock(&fMutex); | ||||
| if (res1 != 0) { | if (res1 != 0) { | ||||
| jack_error("JackPosixProcessSync::LockedTimedWait error err = %s", usec, strerror(res1)); | |||||
| } | |||||
| jack_log("JackPosixProcessSync::TimedWait time out = %ld", usec); | |||||
| gettimeofday(&T0, 0); | |||||
| gettimeofday(&now, 0); | |||||
| unsigned int next_date_usec = now.tv_usec + usec; | |||||
| time.tv_sec = now.tv_sec + (next_date_usec / 1000000); | |||||
| time.tv_nsec = (next_date_usec % 1000000) * 1000; | |||||
| res2 = pthread_cond_timedwait(&fCond, &fMutex, &time); | |||||
| if (res2 != 0) { | |||||
| jack_error("JackPosixProcessSync::LockedTimedWait error usec = %ld err = %s", usec, strerror(res2)); | |||||
| jack_error("JackPosixProcessSync::LockedTimedWait error err = %s", | |||||
| usec, strerror(res1)); | |||||
| } | |||||
| jack_log("JackPosixProcessSync::LockedTimedWait time out = %ld", usec); | |||||
| /* Convert usec argument to timespec */ | |||||
| rel_timeout.tv_sec = usec / 1000000; | |||||
| rel_timeout.tv_nsec = (usec % 1000000) * 1000; | |||||
| /* Calculate absolute monotonic timeout */ | |||||
| res3 = clock_gettime(CLOCK_MONOTONIC, &now_mono); | |||||
| if (res3 != 0) { | |||||
| mono_available = false; | |||||
| } | |||||
| JackPosixTools::TimespecAdd(&now_mono, &rel_timeout, &end_mono); | |||||
| /* pthread_cond_timedwait() is affected by abrupt time jumps, i.e. when the | |||||
| * system time is changed. To protect against this, measure the time | |||||
| * difference between and after the sem_timedwait() call and if it suggests | |||||
| * that there has been a time jump, restart the call. */ | |||||
| if (mono_available) { | |||||
| for (;;) { | |||||
| /* Calculate absolute realtime timeout, assuming no steps */ | |||||
| res3 = clock_gettime(CLOCK_REALTIME, &now_real); | |||||
| assert(res3 == 0); | |||||
| JackPosixTools::TimespecSub(&end_mono, &now_mono, &diff_mono); | |||||
| JackPosixTools::TimespecAdd(&now_real, &diff_mono, &end_real); | |||||
| res2 = pthread_cond_timedwait(&fCond, &fMutex, &end_real); | |||||
| if (res2 != ETIMEDOUT) { | |||||
| break; | |||||
| } | |||||
| /* Compare with monotonic timeout, in case a step happened */ | |||||
| old_errno = errno; | |||||
| res3 = clock_gettime(CLOCK_MONOTONIC, &now_mono); | |||||
| assert(res3 == 0); | |||||
| errno = old_errno; | |||||
| if (JackPosixTools::TimespecCmp(&now_mono, &end_mono) >= 0) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } else { | |||||
| /* CLOCK_MONOTONIC is not supported, do not check for time skips. */ | |||||
| res3 = clock_gettime(CLOCK_REALTIME, &now_real); | |||||
| assert(res3 == 0); | |||||
| JackPosixTools::TimespecAdd(&now_real, &rel_timeout, &end_real); | |||||
| res2 = pthread_cond_timedwait(&fCond, &fMutex, &end_real); | |||||
| } | } | ||||
| gettimeofday(&T1, 0); | |||||
| res1 = pthread_mutex_unlock(&fMutex); | res1 = pthread_mutex_unlock(&fMutex); | ||||
| if (res1 != 0) { | if (res1 != 0) { | ||||
| jack_error("JackPosixProcessSync::LockedTimedWait error err = %s", usec, strerror(res1)); | |||||
| jack_error("JackPosixProcessSync::LockedTimedWait error err = %s", | |||||
| strerror(res1)); | |||||
| } | } | ||||
| jack_log("JackPosixProcessSync::TimedWait finished delta = %5.1lf", | |||||
| (1e6 * T1.tv_sec - 1e6 * T0.tv_sec + T1.tv_usec - T0.tv_usec)); | |||||
| if (res2 != 0) { | |||||
| jack_error("JackPosixProcessSync::LockedTimedWait error usec = %ld err = %s", | |||||
| usec, strerror(res2)); | |||||
| } | |||||
| return (res2 == 0); | |||||
| old_errno = errno; | |||||
| if (mono_available) { | |||||
| res3 = clock_gettime(CLOCK_MONOTONIC, &final_time); | |||||
| assert(res3 == 0); | |||||
| delta = 1e6 * final_time.tv_sec - 1e6 * now_mono.tv_sec + | |||||
| (final_time.tv_nsec - now_mono.tv_nsec) / 1000; | |||||
| } else { | |||||
| res3 = clock_gettime(CLOCK_REALTIME, &final_time); | |||||
| assert(res3 == 0); | |||||
| delta = 1e6 * final_time.tv_sec - 1e6 * now_real.tv_sec + | |||||
| (final_time.tv_nsec - now_real.tv_nsec) / 1000; | |||||
| } | |||||
| errno = old_errno; | |||||
| jack_log("JackPosixProcessSync::LockedTimedWait finished delta = %5.1lf", delta); | |||||
| return res2 == 0; | |||||
| } | } | ||||
| @@ -52,7 +52,6 @@ class JackPosixProcessSync : public JackBasePosixMutex | |||||
| pthread_cond_destroy(&fCond); | pthread_cond_destroy(&fCond); | ||||
| } | } | ||||
| bool TimedWait(long usec); | |||||
| bool LockedTimedWait(long usec); | bool LockedTimedWait(long usec); | ||||
| void Wait(); | void Wait(); | ||||
| @@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
| #include "JackTools.h" | #include "JackTools.h" | ||||
| #include "JackConstants.h" | #include "JackConstants.h" | ||||
| #include "JackError.h" | #include "JackError.h" | ||||
| #include "JackPosixCommon.h" | |||||
| #include <fcntl.h> | #include <fcntl.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <ctype.h> | #include <ctype.h> | ||||
| @@ -122,29 +123,80 @@ bool JackPosixSemaphore::Wait() | |||||
| bool JackPosixSemaphore::TimedWait(long usec) | bool JackPosixSemaphore::TimedWait(long usec) | ||||
| { | { | ||||
| int res; | |||||
| struct timeval now; | |||||
| timespec time; | |||||
| int res; | |||||
| struct timespec rel_timeout, now_mono, end_mono, now_real, end_real; | |||||
| struct timespec diff_mono; | |||||
| if (!fSemaphore) { | if (!fSemaphore) { | ||||
| jack_error("JackPosixSemaphore::TimedWait name = %s already deallocated!!", fName); | jack_error("JackPosixSemaphore::TimedWait name = %s already deallocated!!", fName); | ||||
| return false; | return false; | ||||
| } | } | ||||
| gettimeofday(&now, 0); | |||||
| time.tv_sec = now.tv_sec + usec / 1000000; | |||||
| long tv_usec = (now.tv_usec + (usec % 1000000)); | |||||
| time.tv_sec += tv_usec / 1000000; | |||||
| time.tv_nsec = (tv_usec % 1000000) * 1000; | |||||
| while ((res = sem_timedwait(fSemaphore, &time)) < 0) { | |||||
| jack_error("JackPosixSemaphore::TimedWait err = %s", strerror(errno)); | |||||
| jack_log("JackPosixSemaphore::TimedWait now : %ld %ld ", now.tv_sec, now.tv_usec); | |||||
| jack_log("JackPosixSemaphore::TimedWait next : %ld %ld ", time.tv_sec, time.tv_nsec/1000); | |||||
| if (errno != EINTR) { | |||||
| break; | |||||
| /* Convert usec argument to timespec */ | |||||
| rel_timeout.tv_sec = usec / 1000000; | |||||
| rel_timeout.tv_nsec = (usec % 1000000) * 1000; | |||||
| /* Calculate absolute monotonic timeout */ | |||||
| res = clock_gettime(CLOCK_MONOTONIC, &now_mono); | |||||
| if (res != 0) { | |||||
| /* CLOCK_MONOTONIC is not supported, do not check for time skips. */ | |||||
| res = clock_gettime(CLOCK_REALTIME, &now_real); | |||||
| assert(res == 0); | |||||
| JackPosixTools::TimespecAdd(&now_real, &rel_timeout, &end_real); | |||||
| while ((res = sem_timedwait(fSemaphore, &end_real)) < 0) { | |||||
| if (errno != EINTR) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (res == 0) { | |||||
| return true; | |||||
| } else { | |||||
| goto err; | |||||
| } | } | ||||
| } | } | ||||
| return (res == 0); | |||||
| JackPosixTools::TimespecAdd(&now_mono, &rel_timeout, &end_mono); | |||||
| /* sem_timedwait() is affected by abrupt time jumps, i.e. when the system | |||||
| * time is changed. To protect against this, measure the time difference | |||||
| * between and after the sem_timedwait() call and if it suggests that there | |||||
| * has been a time jump, restart the call. */ | |||||
| for (;;) { | |||||
| /* Calculate absolute realtime timeout, assuming no steps */ | |||||
| res = clock_gettime(CLOCK_REALTIME, &now_real); | |||||
| assert(res == 0); | |||||
| JackPosixTools::TimespecSub(&end_mono, &now_mono, &diff_mono); | |||||
| JackPosixTools::TimespecAdd(&now_real, &diff_mono, &end_real); | |||||
| while ((res = sem_timedwait(fSemaphore, &end_real)) < 0) { | |||||
| if (errno != EINTR) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (res == 0) { | |||||
| return true; | |||||
| } | |||||
| if (errno != ETIMEDOUT) { | |||||
| goto err; | |||||
| } | |||||
| /* Compare with monotonic timeout, in case a step happened */ | |||||
| int old_errno = errno; | |||||
| res = clock_gettime(CLOCK_MONOTONIC, &now_mono); | |||||
| assert(res == 0); | |||||
| errno = old_errno; | |||||
| if (JackPosixTools::TimespecCmp(&now_mono, &end_mono) >= 0) { | |||||
| goto err; | |||||
| } | |||||
| } | |||||
| return true; | |||||
| err: | |||||
| jack_error("JackPosixSemaphore::TimedWait err = %s", strerror(errno)); | |||||
| jack_log("JackPosixSemaphore::TimedWait now : %ld %ld ", now_real.tv_sec, | |||||
| now_real.tv_nsec / 1000); | |||||
| jack_log("JackPosixSemaphore::TimedWait next : %ld %ld ", end_real.tv_sec, | |||||
| end_real.tv_nsec / 1000); | |||||
| return false; | |||||
| } | } | ||||
| // Server side : publish the semaphore in the global namespace | // Server side : publish the semaphore in the global namespace | ||||