Mercurial Hosting > luan
comparison src/luan/modules/ThreadLuan.java @ 1578:c922446f53aa
immutable threading
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Mon, 08 Feb 2021 14:16:19 -0700 |
parents | 8fbcc4747091 |
children | f2a663a4ba9e |
comparison
equal
deleted
inserted
replaced
1577:60e5c324adf9 | 1578:c922446f53aa |
---|---|
15 import goodjava.util.WeakCacheMap; | 15 import goodjava.util.WeakCacheMap; |
16 import luan.Luan; | 16 import luan.Luan; |
17 import luan.LuanFunction; | 17 import luan.LuanFunction; |
18 import luan.LuanTable; | 18 import luan.LuanTable; |
19 import luan.LuanException; | 19 import luan.LuanException; |
20 import luan.LuanCloner; | 20 import luan.LuanMutable; |
21 import luan.LuanCloneable; | |
22 import luan.modules.logging.LuanLogger; | 21 import luan.modules.logging.LuanLogger; |
23 import goodjava.logging.Logger; | 22 import goodjava.logging.Logger; |
24 import goodjava.logging.LoggerFactory; | 23 import goodjava.logging.LoggerFactory; |
25 | 24 |
26 | 25 |
43 } | 42 } |
44 } | 43 } |
45 }; | 44 }; |
46 } | 45 } |
47 | 46 |
48 public static void fork(Luan luan,LuanFunction fn) { | 47 public static void fork(Luan luan,LuanFunction fn) throws LuanException { |
49 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); | 48 luan = new Luan(luan); |
50 luan = (Luan)cloner.get(luan); | 49 LuanMutable.makeImmutable(fn); |
51 fn = (LuanFunction)cloner.get(fn); | |
52 exec.execute(runnable(luan,fn)); | 50 exec.execute(runnable(luan,fn)); |
53 } | 51 } |
54 | 52 |
55 private static final Map<String,ScheduledFuture> scheduleds = new WeakCacheMap<String,ScheduledFuture>(); | 53 private static final Map<String,ScheduledFuture> scheduleds = new WeakCacheMap<String,ScheduledFuture>(); |
56 | 54 |
58 boolean b = sf.cancel(false); | 56 boolean b = sf.cancel(false); |
59 if( !sf.isCancelled() ) | 57 if( !sf.isCancelled() ) |
60 logger.error(src+" cancel="+b+" isCancelled="+sf.isCancelled()+" isDone="+sf.isDone()+" "+sf); | 58 logger.error(src+" cancel="+b+" isCancelled="+sf.isCancelled()+" isDone="+sf.isDone()+" "+sf); |
61 } | 59 } |
62 | 60 |
61 public static synchronized void schedule_closure(Luan luan,LuanFunction initFn,LuanTable options) | |
62 throws LuanException | |
63 { | |
64 final Luan newLuan = new Luan(luan); | |
65 LuanMutable.makeImmutable(initFn); | |
66 LuanFunction fn = (LuanFunction)initFn.call(newLuan); | |
67 scheduleFn(luan,newLuan,fn,options); | |
68 } | |
69 | |
63 public static synchronized void schedule(Luan luan,LuanFunction fn,LuanTable options) | 70 public static synchronized void schedule(Luan luan,LuanFunction fn,LuanTable options) |
71 throws LuanException | |
72 { | |
73 final Luan newLuan = new Luan(luan); | |
74 LuanMutable.makeImmutable(fn); | |
75 scheduleFn(luan,newLuan,fn,options); | |
76 } | |
77 | |
78 private static synchronized void scheduleFn(Luan luan,final Luan newLuan,LuanFunction fn,LuanTable options) | |
64 throws LuanException | 79 throws LuanException |
65 { | 80 { |
66 options = new LuanTable(options); | 81 options = new LuanTable(options); |
67 Number delay = Utils.removeNumber(options,"delay"); | 82 Number delay = Utils.removeNumber(options,"delay"); |
68 Number repeatingDelay = Utils.removeNumber(options,"repeating_delay"); | 83 Number repeatingDelay = Utils.removeNumber(options,"repeating_delay"); |
75 if( id != null ) { | 90 if( id != null ) { |
76 ScheduledFuture sf = scheduleds.remove(id); | 91 ScheduledFuture sf = scheduleds.remove(id); |
77 if( sf != null ) | 92 if( sf != null ) |
78 cancel(sf,"id "+id); | 93 cancel(sf,"id "+id); |
79 } | 94 } |
80 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); | 95 final Runnable r = runnable(newLuan,fn); |
81 final Luan newLuan = (Luan)cloner.clone(luan); | |
82 final LuanFunction newFn = (LuanFunction)cloner.get(fn); | |
83 final Runnable r = runnable(newLuan,newFn); | |
84 final ScheduledFuture sf; | 96 final ScheduledFuture sf; |
85 if( repeatingDelay != null ) { | 97 if( repeatingDelay != null ) { |
86 if( delay==null ) | 98 if( delay==null ) |
87 delay = repeatingDelay; | 99 delay = repeatingDelay; |
88 sf = scheduler.scheduleWithFixedDelay(r,delay.longValue(),repeatingDelay.longValue(),TimeUnit.MILLISECONDS); | 100 sf = scheduler.scheduleWithFixedDelay(r,delay.longValue(),repeatingDelay.longValue(),TimeUnit.MILLISECONDS); |
104 luan.registry().put(c,c); // cancel on gc | 116 luan.registry().put(c,c); // cancel on gc |
105 if( id != null ) | 117 if( id != null ) |
106 scheduleds.put(id,sf); | 118 scheduleds.put(id,sf); |
107 } | 119 } |
108 | 120 |
109 /* | |
110 public static class GlobalMap { | |
111 | |
112 private static class Value { | |
113 final long time = System.currentTimeMillis(); | |
114 final Object v; | |
115 | |
116 Value(Object v) { | |
117 this.v = v; | |
118 } | |
119 } | |
120 | |
121 public long timeout = 60000L; // one minute | |
122 private Map<String,Value> map = new LinkedHashMap<String,Value>() { | |
123 protected boolean removeEldestEntry(Map.Entry<String,Value> eldest) { | |
124 return eldest.getValue().time < System.currentTimeMillis() - timeout; | |
125 } | |
126 }; | |
127 | |
128 public synchronized Object get(String key) { | |
129 Value val = map.get(key); | |
130 return val==null ? null : val.v; | |
131 } | |
132 | |
133 public synchronized Object put(String key,Object v) throws LuanException { | |
134 Value val; | |
135 if( v == null ) { | |
136 val = map.remove(key); | |
137 } else { | |
138 if( !(v instanceof String || v instanceof Boolean || v instanceof Number) ) | |
139 throw new LuanException("can't assign type "+Luan.type(v)+" to Thread.global"); | |
140 val = map.put(key,new Value(v)); | |
141 } | |
142 return val==null ? null : val.v; | |
143 } | |
144 } | |
145 */ | |
146 | 121 |
147 public static void sleep(long millis) throws InterruptedException { | 122 public static void sleep(long millis) throws InterruptedException { |
148 Thread.sleep(millis); | 123 Thread.sleep(millis); |
149 } | 124 } |
150 | 125 |
151 | |
152 private static class Unsafe { | |
153 private final String reason; | |
154 | |
155 Unsafe(String reason) { | |
156 this.reason = reason; | |
157 } | |
158 } | |
159 | |
160 private static Object makeSafe(Object v) throws LuanException { | |
161 if( v instanceof LuanTable ) { | |
162 LuanTable tbl = (LuanTable)v; | |
163 if( tbl.getMetatable() != null ) | |
164 return new Unsafe("table with metatable"); | |
165 LuanTable rtn = new LuanTable(); | |
166 for( Map.Entry entry : tbl.rawIterable() ) { | |
167 Object key = makeSafe( entry.getKey() ); | |
168 if( key instanceof Unsafe ) | |
169 return key; | |
170 Object value = makeSafe( entry.getValue() ); | |
171 if( value instanceof Unsafe ) | |
172 return value; | |
173 rtn.rawPut(key,value); | |
174 } | |
175 return rtn; | |
176 } else if( v instanceof Object[] ) { | |
177 Object[] a = (Object[])v; | |
178 for( int i=0; i<a.length; i++ ) { | |
179 Object obj = makeSafe(a[i]); | |
180 if( obj instanceof Unsafe ) | |
181 return obj; | |
182 a[i] = obj; | |
183 } | |
184 return a; | |
185 } else { | |
186 if( v instanceof LuanCloneable ) | |
187 return new Unsafe("type "+Luan.type(v)); | |
188 return v; | |
189 } | |
190 } | |
191 | 126 |
192 public static final class Callable { | 127 public static final class Callable { |
193 private long expires; | 128 private long expires; |
194 private final Luan luan = new Luan(); | 129 private final Luan luan = new Luan(); |
195 private final LuanTable fns; | 130 private final LuanTable fns; |
196 | 131 |
197 Callable(LuanTable fns) { | 132 Callable(LuanFunction initFn) throws LuanException { |
198 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); | 133 LuanMutable.makeImmutable(initFn); |
199 this.fns = (LuanTable)cloner.get(fns); | 134 this.fns = (LuanTable)initFn.call(luan); |
200 } | 135 } |
201 | 136 |
202 public synchronized Object call(Luan callerLuan,String fnName,Object... args) throws LuanException { | 137 public synchronized Object call(Luan callerLuan,String fnName,Object... args) throws LuanException { |
203 Object obj = makeSafe(args); | 138 LuanMutable.makeImmutable(args); |
204 if( obj instanceof Unsafe ) | |
205 throw new LuanException("can't pass "+((Unsafe)obj).reason+" to global_callable "+Arrays.asList(args)); | |
206 args = (Object[])obj; | |
207 Object f = fns.get(luan,fnName); | 139 Object f = fns.get(luan,fnName); |
208 if( f == null ) | 140 if( f == null ) |
209 throw new LuanException("function '"+fnName+"' not found in global_callable"); | 141 throw new LuanException("function '"+fnName+"' not found in global_callable"); |
210 if( !(f instanceof LuanFunction) ) | 142 if( !(f instanceof LuanFunction) ) |
211 throw new LuanException("value of '"+fnName+"' not a function in global_callable"); | 143 throw new LuanException("value of '"+fnName+"' not a function in global_callable"); |
212 LuanFunction fn = (LuanFunction)f; | 144 LuanFunction fn = (LuanFunction)f; |
213 Object rtn = fn.call(luan,args); | 145 Object rtn = fn.call(luan,args); |
214 rtn = makeSafe(rtn); | 146 LuanMutable.makeImmutable(rtn); |
215 if( rtn instanceof Unsafe ) | |
216 throw new LuanException("can't return "+((Unsafe)rtn).reason+" from global_callable"); | |
217 return rtn; | 147 return rtn; |
218 } | 148 } |
219 } | 149 } |
220 | 150 |
221 private static Map<String,Callable> callableMap = new HashMap<String,Callable>(); | 151 private static Map<String,Callable> callableMap = new HashMap<String,Callable>(); |
227 if( callable.expires < now ) | 157 if( callable.expires < now ) |
228 iter.remove(); | 158 iter.remove(); |
229 } | 159 } |
230 } | 160 } |
231 | 161 |
232 public static synchronized Callable globalCallable(String name,LuanTable fns,long timeout) { | 162 public static synchronized Callable globalCallable(String name,LuanFunction initFn,long timeout) throws LuanException { |
233 Callable callable = callableMap.get(name); | 163 Callable callable = callableMap.get(name); |
234 if( callable == null ) { | 164 if( callable == null ) { |
235 sweep(); | 165 sweep(); |
236 callable = new Callable(fns); | 166 callable = new Callable(initFn); |
237 callableMap.put(name,callable); | 167 callableMap.put(name,callable); |
238 } | 168 } |
239 callable.expires = System.currentTimeMillis() + timeout; | 169 callable.expires = System.currentTimeMillis() + timeout; |
240 return callable; | 170 return callable; |
241 } | 171 } |