File: cyclic.l

package info (click to toggle)
euslisp 9.31%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 55,448 kB
  • sloc: ansic: 41,610; lisp: 3,339; makefile: 286; sh: 238; asm: 138; python: 53
file content (150 lines) | stat: -rw-r--r-- 3,778 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
;; cyclic.l
;; cyclic task dispatcher using the interval timer
;; 1995 (c), Toshihiro Matsui, Electrotechnical Laboratory
;;
;; This file should be loaded into the system package.
;;

(list "@(#)$Id$")
(export '(itimer start-timer stop-timer deftimer behavior real-time
	  *itimers* *itimer-tick* *itimer-count* ))


(defconstant *itimer-tick* 0.1	"minimum timer interval")
(defparameter *itimers* nil)
(defparameter *itimer-running* t)
(defparameter *itimer-sem* (sys:make-semaphore))
(defparameter *itimer-count* 0)


(defclass itimer :super propertied-object
	:slots (interval current timer-sem func args
		real-time running run-count missed thr deleted))

(defmethod itimer
 (:init (int &optional f)
   (send self :interval int)
   (setq run-count 0
	 current   interval
	 running t
	 func f
	 missed 0
	 deleted nil
	 )
   (unless timer-sem (setq timer-sem (sys:make-semaphore)))
   (unless thr 
        (sys:make-thread 1)
	(setq thr (sys:thread 'timer-func self)))
   (unless args (setq args (list self)))
   self)
 (:delete ()
    (setq *itimers* (delete self *itimers*))
    (setq deleted t)
    (sys:sema-post timer-sem)
    (sys:wait-thread thr)
    )
 (:priority (&optional n) (send thr :priority n))
 (:running () running)
 (:tick ()
    (when (and running (zerop (decf current)))
	(setq current interval)
	(incf run-count)
	(setq real-time (* run-count *itimer-tick* interval))
	(sys:sema-post timer-sem)))
 (:func (&optional f)
    (if f (setq func f))
    func)
 (:args (&rest a) (setq args a) args)
 (:count () run-count)
 (:stop () (setq running nil))
 (:start () (setq running t))
 (:interval (&optional i)
    (if i 
	(setq interval  (round (/ i *itimer-tick*))))
    (* interval *itimer-tick*) )
 (:run ()
    (incf missed (aref timer-sem 0))
    (setf (aref timer-sem 0) 0)
    (if func (apply func args)))
 (:thread-waiting ()
    (while (not deleted)
	(sys:sema-wait timer-sem)
	(send self :run)))
 )


(defclass behavior :super itimer
	:slots (event-sem state))

(defmethod behavior
 (:init (&rest args)
   (send-super* :init args)
   (setq running nil)
   (setq event-sem (sys:make-semaphore))
   self)
 (:delete () (setq deleted t) (sys:sema-post event-sem)
    (send-super :delete))
 (:initiate ()
    (cond (running nil)
	  (t  (sys:sema-post event-sem) t)))
 (:starting () 
    (setq running t
	  run-count 0)   )
 (:thread-waiting ()
    (while (not deleted)
	(sys:sema-wait event-sem)
	(when (not deleted)
           (send self :starting)
	   (while running
	      (sys:sema-wait timer-sem)
	      (send self :run)))))
   )


(defun timer-func (timer)
   (send timer :thread-waiting)
   (format t ";timer-func finished ~s~%" timer) )
      

(defun itimer-handler ()	;run by an independent thread
   (while t
      (sys:sema-wait *itimer-sem*)
      (incf *itimer-count*)
      (when *itimer-running*
	 (dolist (it *itimers*)
	    (send it :tick)))))

(defun find-itimer (name)
   (find-if #'(lambda (it) (eql (send it :name) name)) *itimers*))

(defmacro deftimer (name  klass interval &rest init-args)
   `(let ((it (find-itimer ',name)) (func))
	(if (null it) 
	    (setq it 
	    (if (and (boundp ',klass) (subclassp ,klass itimer))
		(instantiate ,klass)
		(progn (setq func ',klass) (instantiate itimer)))))
        (pushnew (setq ,name (send* it :init ,interval func ,init-args))
		 *itimers*)
	(send  it :name ',name))
)


(defun init-cyclic ()
   (sys:make-thread 3)
   (sys:thread-no-wait 'itimer-handler)
   (unix:signal unix::sigalrm *itimer-sem* 20)
	; 4 for restart 16 for nodefer
   )

(defun start-timer ()
;   (dolist (it *itimers*)
;         (setf (itimer-running it ) t))
   (unix:setitimer 0 1 *itimer-tick*))

(defun stop-timer ()
   (unix:setitimer 0 0 0)
;   (dolist (it *itimers*)
;    (setf (itimer-running it ) nil))
)