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 }