#! /usr/bin/env stap
# Copyright (C) 2009-2018 Red Hat, Inc.
# Written by Ulrich Drepper <drepper@redhat.com>
# Modified by William Cohen <wcohen@redhat.com>

global process, timeout_count, to
global poll_timeout, epoll_timeout, select_timeout, itimer_timeout
global nanosleep_timeout, futex_timeout, signal_timeout

probe syscall.{poll,epoll_wait} {
  if (timeout) to[pid()]=timeout
}

probe syscall.poll.return {
  if (retval == 0 && to[pid()] > 0 ) {
    poll_timeout[pid()]++
    timeout_count[pid()]++
    process[pid()] = execname()
    delete to[pid()]
  }
}

probe syscall.epoll_wait.return {
  if (retval == 0 && to[pid()] > 0 ) {
    epoll_timeout[pid()]++
    timeout_count[pid()]++
    process[pid()] = execname()
    delete to[pid()]
  }
}

probe syscall.select.return {
  if (retval == 0) {
    select_timeout[pid()]++
    timeout_count[pid()]++
    process[pid()] = execname()
  }
}

probe syscall.futex.return {
  if (errno_str(retval) == "ETIMEDOUT") {
    futex_timeout[pid()]++
    timeout_count[pid()]++
    process[pid()] = execname()
  }
}

probe syscall.nanosleep.return {
  if (retval == 0) {
    nanosleep_timeout[pid()]++
    timeout_count[pid()]++
    process[pid()] = execname()
  }
}

probe kernel.function("it_real_fn") {
  itimer_timeout[pid()]++
  timeout_count[pid()]++
  process[pid()] = execname()
}

probe syscall.rt_sigtimedwait.return {
  if (errno_str(retval) == "EAGAIN") {
    signal_timeout[pid()]++
    timeout_count[pid()]++
    process[pid()] = execname()
  }
}

probe syscall.exit {
  if (pid() in process) {
    delete process[pid()]
    delete timeout_count[pid()]
    delete poll_timeout[pid()]
    delete epoll_timeout[pid()]
    delete select_timeout[pid()]
    delete itimer_timeout[pid()]
    delete futex_timeout[pid()]
    delete nanosleep_timeout[pid()]
    delete signal_timeout[pid()]
  }
}

probe timer.s(1) {
  ansi_clear_screen()
  printf ("  pid |   poll  select   epoll  itimer   futex nanosle  signal| process\n")
  foreach (p in timeout_count- limit 20) {
     printf ("%5d |%7d %7d %7d %7d %7d %7d %7d| %-.38s\n", p,
              poll_timeout[p], select_timeout[p],
              epoll_timeout[p], itimer_timeout[p],
              futex_timeout[p], nanosleep_timeout[p],
              signal_timeout[p], process[p])
  }
}

global prom_arr

probe prometheus {
  foreach (p in timeout_count- limit 20) {
    prom_arr[poll_timeout[p], select_timeout[p],
             epoll_timeout[p], itimer_timeout[p],
	     futex_timeout[p], nanosleep_timeout[p],
	     signal_timeout[p]] = process[p]
  }

  @prometheus_dump_array7(prom_arr, "process_timeouts", "poll_timeout", "select_timeout",
		          "epoll_timeout", "itimer_timeout",
			  "futex_timeout", "nanosleep_timeout",
			  "signal_timeout")
  delete prom_arr
}
