//   timerRunning    -> wait until status changes
 //   timerMoving     -> wait until status changes
 //   timerModifying  -> panic: concurrent deltimer/modtimer calls
+// modtimer:
+//   timerWaiting    -> timerModifying -> timerModifiedXX
+//   timerModifiedXX -> timerModifying -> timerModifiedYY
+//   timerNoStatus   -> timerWaiting
+//   timerRemoved    -> timerWaiting
+//   timerRunning    -> wait until status changes
+//   timerMoving     -> wait until status changes
+//   timerRemoving   -> wait until status changes
+//   timerDeleted    -> panic: concurrent modtimer/deltimer calls
+//   timerModifying  -> panic: concurrent modtimer calls
 
 // Values for the timer status field.
 const (
        }
        t.status = timerWaiting
 
+       addInitializedTimer(t)
+}
+
+// addInitializedTimer adds an initialized timer to the current P.
+func addInitializedTimer(t *timer) {
        when := t.when
 
        pp := getg().m.p.ptr()
                                return true
                        }
                case timerModifiedEarlier:
+                       tpp := t.pp.ptr()
                        if atomic.Cas(&t.status, s, timerModifying) {
+                               atomic.Xadd(&tpp.adjustTimers, -1)
                                if !atomic.Cas(&t.status, timerModifying, timerDeleted) {
                                        badTimer()
                                }
        return true, ok
 }
 
+// modtimer modifies an existing timer.
+// This is called by the netpoll code.
 func modtimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
        if oldTimers {
                modtimerOld(t, when, period, f, arg, seq)
                return
        }
-       throw("new modtimer not yet implemented")
+
+       if when < 0 {
+               when = maxWhen
+       }
+
+       status := uint32(timerNoStatus)
+       wasRemoved := false
+loop:
+       for {
+               switch status = atomic.Load(&t.status); status {
+               case timerWaiting, timerModifiedEarlier, timerModifiedLater:
+                       if atomic.Cas(&t.status, status, timerModifying) {
+                               break loop
+                       }
+               case timerNoStatus, timerRemoved:
+                       // Timer was already run and t is no longer in a heap.
+                       // Act like addtimer.
+                       wasRemoved = true
+                       atomic.Store(&t.status, timerWaiting)
+                       break loop
+               case timerRunning, timerRemoving, timerMoving:
+                       // The timer is being run or moved, by a different P.
+                       // Wait for it to complete.
+                       osyield()
+               case timerDeleted:
+                       // Simultaneous calls to modtimer and deltimer.
+                       badTimer()
+               case timerModifying:
+                       // Multiple simultaneous calls to modtimer.
+                       badTimer()
+               default:
+                       badTimer()
+               }
+       }
+
+       t.period = period
+       t.f = f
+       t.arg = arg
+       t.seq = seq
+
+       if wasRemoved {
+               t.when = when
+               addInitializedTimer(t)
+       } else {
+               // The timer is in some other P's heap, so we can't change
+               // the when field. If we did, the other P's heap would
+               // be out of order. So we put the new when value in the
+               // nextwhen field, and let the other P set the when field
+               // when it is prepared to resort the heap.
+               t.nextwhen = when
+
+               newStatus := uint32(timerModifiedLater)
+               if when < t.when {
+                       newStatus = timerModifiedEarlier
+               }
+
+               // Update the adjustTimers field.  Subtract one if we
+               // are removing a timerModifiedEarlier, add one if we
+               // are adding a timerModifiedEarlier.
+               tpp := t.pp.ptr()
+               adjust := int32(0)
+               if status == timerModifiedEarlier {
+                       adjust--
+               }
+               if newStatus == timerModifiedEarlier {
+                       adjust++
+               }
+               if adjust != 0 {
+                       atomic.Xadd(&tpp.adjustTimers, adjust)
+               }
+
+               // Set the new status of the timer.
+               if !atomic.Cas(&t.status, timerModifying, newStatus) {
+                       badTimer()
+               }
+
+               // If the new status is earlier, wake up the poller.
+               if newStatus == timerModifiedEarlier {
+                       wakeNetPoller(when)
+               }
+       }
 }
 
 func modtimerOld(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {