periodic.c 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "stdinc.h"
  10. #include "dat.h"
  11. #include "fns.h"
  12. #include "error.h"
  13. struct Periodic {
  14. VtLock *lk;
  15. int die; /* flag: quit if set */
  16. void (*f)(void*); /* call this each period */
  17. void *a; /* argument to f */
  18. int msec; /* period */
  19. };
  20. static void periodicThread(void *a);
  21. Periodic *
  22. periodicAlloc(void (*f)(void*), void *a, int msec)
  23. {
  24. Periodic *p;
  25. p = vtMemAllocZ(sizeof(Periodic));
  26. p->lk = vtLockAlloc();
  27. p->f = f;
  28. p->a = a;
  29. p->msec = msec;
  30. if(p->msec < 10)
  31. p->msec = 10;
  32. vtThread(periodicThread, p);
  33. return p;
  34. }
  35. void
  36. periodicKill(Periodic *p)
  37. {
  38. if(p == nil)
  39. return;
  40. vtLock(p->lk);
  41. p->die = 1;
  42. vtUnlock(p->lk);
  43. }
  44. static void
  45. periodicFree(Periodic *p)
  46. {
  47. vtLockFree(p->lk);
  48. vtMemFree(p);
  49. }
  50. static void
  51. periodicThread(void *a)
  52. {
  53. Periodic *p = a;
  54. int64_t t, ct, ts; /* times in ms. */
  55. vtThreadSetName("periodic");
  56. ct = nsec() / 1000000;
  57. t = ct + p->msec; /* call p->f at or after this time */
  58. for(;;){
  59. ts = t - ct; /* ms. to next cycle's start */
  60. if(ts > 1000)
  61. ts = 1000; /* bound sleep duration */
  62. if(ts > 0)
  63. sleep(ts); /* wait for cycle's start */
  64. vtLock(p->lk);
  65. if(p->die){
  66. vtUnlock(p->lk);
  67. break;
  68. }
  69. ct = nsec() / 1000000;
  70. if(t <= ct){ /* due to call p->f? */
  71. p->f(p->a);
  72. ct = nsec() / 1000000;
  73. while(t <= ct) /* advance t to future cycle start */
  74. t += p->msec;
  75. }
  76. vtUnlock(p->lk);
  77. }
  78. periodicFree(p);
  79. }