diff -urNp linuxcnc-2.7.11.orig/src/rtapi/rtapi.h linuxcnc-2.7.11/src/rtapi/rtapi.h
--- linuxcnc-2.7.11.orig/src/rtapi/rtapi.h	2017-07-28 06:37:30.000000000 +0200
+++ linuxcnc-2.7.11/src/rtapi/rtapi.h	2018-03-09 11:13:47.663003028 +0100
@@ -473,6 +473,26 @@ RTAPI_BEGIN_DECLS
 */
     extern int rtapi_task_self(void);
 
+#if defined(RTAPI_USPACE) || defined(USPACE)
+
+#define RTAPI_TASK_PLL_SUPPORT
+
+/** 'rtapi_task_pll_get_reference()' gets the reference timestamp
+    for the start of the current cycle.
+    Returns 0 if not called from within task context or on
+    platforms that do not support this.
+*/
+    extern long long rtapi_task_pll_get_reference(void);
+
+/** 'rtapi_task_pll_set_correction()' sets the correction value for
+    the next scheduling cycle of the current task. This could be
+    used to synchronize the task cycle to external sources.
+    Returns -EINVAL if not called from within task context or on
+    platforms that do not support this.
+*/
+    extern int rtapi_task_pll_set_correction(long value);
+#endif /* USPACE */
+
 #endif /* RTAPI */
 
 /***********************************************************************
diff -urNp linuxcnc-2.7.11.orig/src/rtapi/rtapi_uspace.hh linuxcnc-2.7.11/src/rtapi/rtapi_uspace.hh
--- linuxcnc-2.7.11.orig/src/rtapi/rtapi_uspace.hh	2017-07-28 06:37:30.000000000 +0200
+++ linuxcnc-2.7.11/src/rtapi/rtapi_uspace.hh	2018-03-09 11:13:59.219002690 +0100
@@ -47,6 +47,8 @@ struct RtapiApp
     virtual int task_pause(int task_id) = 0;
     virtual int task_resume(int task_id) = 0;
     virtual int task_self() = 0;
+    virtual long long task_pll_get_reference(void) = 0;
+    virtual int task_pll_set_correction(long value) = 0;
     virtual void wait() = 0;
     virtual unsigned char do_inb(unsigned int port) = 0;
     virtual void do_outb(unsigned char value, unsigned int port) = 0;
@@ -71,6 +73,8 @@ struct rtapi_task {
   long period;
   struct timespec nextstart;
   unsigned ratio;
+  long pll_correction;
+  long pll_correction_limit;
   void *arg;
   void (*taskcode) (void*);	/* pointer to task function */
 };
diff -urNp linuxcnc-2.7.11.orig/src/rtapi/uspace_rtapi_app.cc linuxcnc-2.7.11/src/rtapi/uspace_rtapi_app.cc
--- linuxcnc-2.7.11.orig/src/rtapi/uspace_rtapi_app.cc	2017-07-28 06:37:30.000000000 +0200
+++ linuxcnc-2.7.11/src/rtapi/uspace_rtapi_app.cc	2018-03-09 11:14:33.823001678 +0100
@@ -519,6 +519,8 @@ struct Posix : RtapiApp
     int task_pause(int task_id);
     int task_resume(int task_id);
     int task_self();
+    long long task_pll_get_reference(void);
+    int task_pll_set_correction(long value);
     void wait();
     unsigned char do_inb(unsigned int port);
     void do_outb(unsigned char value, unsigned int port);
@@ -830,6 +832,10 @@ int Posix::task_start(int task_id, unsig
   task->period = period_nsec;
   task->ratio = period_nsec / period;
 
+  // limit PLL correction values to +/-1% of cycle time
+  task->pll_correction_limit = period_nsec / 100;
+  task->pll_correction = 0;
+
   struct sched_param param;
   memset(&param, 0, sizeof(param));
   param.sched_priority = task->prio;
@@ -906,7 +912,7 @@ void *Posix::wrapper(void *arg)
 
   struct timespec now;
   clock_gettime(RTAPI_CLOCK, &now);
-  advance_clock(task->nextstart, now, task->period);
+  advance_clock(task->nextstart, now, task->period + task->pll_correction);
 
   /* call the task function with the task argument */
   (task->taskcode) (task->arg);
@@ -929,6 +935,21 @@ int Posix::task_self() {
     return task - task_array;
 }
 
+long long Posix::task_pll_get_reference(void) {
+    struct rtapi_task *task = reinterpret_cast<rtapi_task*>(pthread_getspecific(key));
+    if(!task) return 0;
+    return task->nextstart.tv_sec * 1000000000LL + task->nextstart.tv_nsec;
+}
+
+int Posix::task_pll_set_correction(long value) {
+    struct rtapi_task *task = reinterpret_cast<rtapi_task*>(pthread_getspecific(key));
+    if(!task) return -EINVAL;
+    if (value > task->pll_correction_limit) value = task->pll_correction_limit;
+    if (value < -(task->pll_correction_limit)) value = -(task->pll_correction_limit);
+    task->pll_correction = value;
+    return 0;
+}
+
 static bool ts_less(const struct timespec &ta, const struct timespec &tb) {
     if(ta.tv_sec < tb.tv_sec) return 1;
     if(ta.tv_sec > tb.tv_sec) return 0;
@@ -940,7 +961,7 @@ void Posix::wait() {
         pthread_mutex_unlock(&thread_lock);
     pthread_testcancel();
     struct rtapi_task *task = reinterpret_cast<rtapi_task*>(pthread_getspecific(key));
-    advance_clock(task->nextstart, task->nextstart, task->period);
+    advance_clock(task->nextstart, task->nextstart, task->period + task->pll_correction);
     struct timespec now;
     clock_gettime(RTAPI_CLOCK, &now);
     if(ts_less(task->nextstart, now))
@@ -1040,6 +1061,16 @@ int rtapi_task_self()
     return App().task_self();
 }
 
+long long rtapi_task_pll_get_reference(void)
+{
+    return App().task_pll_get_reference();
+}
+
+int rtapi_task_pll_set_correction(long value)
+{
+    return App().task_pll_set_correction(value);
+}
+
 void rtapi_wait(void)
 {
     App().wait();
