Commit 81bd6d5a4e5d41556d40914cdd1bb74e01b6157d
1 parent
b9f7794f
New version 1.14: new form of 'delegate' taking priorities into account (see anu…
…bis_dev/manuals/en/Anubis-doc-1-13.pdf)
Showing
22 changed files
with
671 additions
and
204 deletions
Show diff stats
anubis_dev/compiler/src/compil.h
| ... | ... | @@ -417,7 +417,9 @@ extern Expr linecol(void); |
| 417 | 417 | item(wait_for)\ |
| 418 | 418 | item(give_up)\ |
| 419 | 419 | item(delegate)\ |
| 420 | + item(delegatep)\ | |
| 420 | 421 | item(start)\ |
| 422 | + item(startp)\ | |
| 421 | 423 | item(finish)\ |
| 422 | 424 | item(copy_stack_ptr)\ |
| 423 | 425 | item(copy_stack_mixed)\ |
| ... | ... | @@ -983,71 +985,7 @@ extern int max_tpair_load; |
| 983 | 985 | #define cdr7(x) (cdr(cdr6(x))) |
| 984 | 986 | |
| 985 | 987 | extern Expr nthcdr(Expr n, Expr l); // get n-th cdr of l |
| 986 | - | |
| 987 | -#define term_switch(term,name)\ | |
| 988 | - switch(car(term)) {\ | |
| 989 | - case alt_number: goto alt_number_##name;\ | |
| 990 | - case protect: goto protect_##name;\ | |
| 991 | - case lock: goto lock_##name;\ | |
| 992 | - case alert: goto alert_##name;\ | |
| 993 | - case debug_avm: goto debug_avm_##name;\ | |
| 994 | - case terminal: goto terminal_##name;\ | |
| 995 | - case integer: goto integer_##name;\ | |
| 996 | - case fpnum: goto fpnum_##name;\ | |
| 997 | - case symbol: goto symbol_##name;\ | |
| 998 | - case of_type: goto of_type_##name;\ | |
| 999 | - case constructor: goto constructor_##name;\ | |
| 1000 | - case lambda: goto lambda_##name;\ | |
| 1001 | - case app: goto app_##name;\ | |
| 1002 | - case cond: goto cond_##name;\ | |
| 1003 | - case select_cond: goto select_cond_##name;\ | |
| 1004 | - case with: goto with_##name;\ | |
| 1005 | - case string: goto string_##name;\ | |
| 1006 | - case anb_read: goto anb_read_##name;\ | |
| 1007 | - case anb_write: goto anb_write_##name;\ | |
| 1008 | - case wait_for: goto wait_for_##name;\ | |
| 1009 | - case delegate: goto delegate_##name;\ | |
| 1010 | - case set: goto set_##name;\ | |
| 1011 | - case omega_true: goto omega_true_##name;\ | |
| 1012 | - case omega_false: goto omega_false_##name;\ | |
| 1013 | - case serialize: goto serialize_##name;\ | |
| 1014 | - case unserialize: goto unserialize_##name;\ | |
| 1015 | - case bit_width: goto bit_width_##name;\ | |
| 1016 | - case indirect_type: goto indirect_type_##name;\ | |
| 1017 | - case vcopy: goto vcopy_##name;\ | |
| 1018 | - default: internal_error("Unknown term",term); }\ | |
| 1019 | - | |
| 1020 | - | |
| 1021 | -#define interp_switch(head,name)\ | |
| 1022 | - switch(car(head)) {\ | |
| 1023 | - case alt_number: goto alt_number_##name;\ | |
| 1024 | - case protect: goto protect_##name;\ | |
| 1025 | - case lock: goto lock_##name;\ | |
| 1026 | - case avm: goto avm_##name;\ | |
| 1027 | - case debug_avm: goto debug_avm_##name;\ | |
| 1028 | - case terminal: goto terminal_##name;\ | |
| 1029 | - case operation: goto operation_##name;\ | |
| 1030 | - case string: goto string_##name;\ | |
| 1031 | - case anb_int32: goto int32_##name;\ | |
| 1032 | - case small_datum: goto small_datum_##name;\ | |
| 1033 | - case fpnum: goto fpnum_##name;\ | |
| 1034 | - case local: goto local_##name;\ | |
| 1035 | - case app: goto app_##name;\ | |
| 1036 | - case cond: goto cond_##name;\ | |
| 1037 | - case select_cond_interp: goto select_cond_interp_##name;\ | |
| 1038 | - case with: goto with_##name;\ | |
| 1039 | - case constructor: goto constructor_##name;\ | |
| 1040 | - case anb_read: goto anb_read_##name;\ | |
| 1041 | - case anb_write: goto anb_write_##name;\ | |
| 1042 | - case wait_for: goto wait_for_##name;\ | |
| 1043 | - case delegate: goto delegate_##name;\ | |
| 1044 | - case serialize: goto serialize_##name;\ | |
| 1045 | - case unserialize: goto unserialize_##name;\ | |
| 1046 | - case bit_width: goto bit_width_##name;\ | |
| 1047 | - case indirect_type: goto indirect_type_##name;\ | |
| 1048 | - case vcopy: goto vcopy_##name;\ | |
| 1049 | - default: internal_error("Unknown interpretation head",head); }\ | |
| 1050 | - | |
| 988 | + | |
| 1051 | 989 | |
| 1052 | 990 | extern int length(Expr list); |
| 1053 | 991 | |
| ... | ... | @@ -1470,7 +1408,7 @@ extern Expr _symbols_in_interp(Expr); |
| 1470 | 1408 | debug(implems[id].offline_code); } while(0) |
| 1471 | 1409 | |
| 1472 | 1410 | |
| 1473 | -extern Expr _debug(char *,Expr, char *filename, int line); | |
| 1411 | +extern Expr _debug(const char *,Expr, char *filename, int line); | |
| 1474 | 1412 | extern void _debug_nl(char *file, int line); |
| 1475 | 1413 | extern void _debug_msg(char *msg); |
| 1476 | 1414 | |
| ... | ... | @@ -1916,7 +1854,8 @@ extern const char *msgtext_unused_named_resurgent[]; |
| 1916 | 1854 | extern const char *msgtext_duplicate_type_name[]; |
| 1917 | 1855 | extern const char *msgtext_replaced_by[]; |
| 1918 | 1856 | extern const char *msgtext_undefined_macro[]; |
| 1919 | - | |
| 1857 | +extern const char *msgtext_priority_not_word8[]; | |
| 1858 | +extern const char *msgtext_priority_ambiguous[]; | |
| 1920 | 1859 | |
| 1921 | 1860 | |
| 1922 | 1861 | #ifdef __cplusplus | ... | ... |
anubis_dev/compiler/src/compile.c
| ... | ... | @@ -2985,6 +2985,66 @@ Expr compile_term(Expr head, |
| 2985 | 2985 | |
| 2986 | 2986 | /*---------------------------------------------------------------------------*/ |
| 2987 | 2987 | |
| 2988 | + case delegatep: | |
| 2989 | + { | |
| 2990 | + /* (delegate <lc> <head priority> <head (delegated)> . <head (body)>) */ | |
| 2991 | + | |
| 2992 | + /* | |
| 2993 | + same as 'delegate' but with priority. The priority level must be computed | |
| 2994 | + first (not push into the stack). Uses 'startp' instead of 'start' | |
| 2995 | + should produce this: | |
| 2996 | + | |
| 2997 | + <d virtual copies in stack of parent machine> | |
| 2998 | + [priority] priority in R | |
| 2999 | + startp d a start a machine with priority (in R), d items in the stack | |
| 3000 | + and jump to 'a' | |
| 3001 | + | |
| 3002 | + [delegated] | |
| 3003 | + <d virtual deletions in stack of child machine> | |
| 3004 | + <deletion of R> (type is that of delegated) | |
| 3005 | + | |
| 3006 | + finish will stop the child machine | |
| 3007 | + | |
| 3008 | + label a: | |
| 3009 | + [body] | |
| 3010 | + | |
| 3011 | + | |
| 3012 | + When 'finished' is executed, there are still 2 words in the stack. Indeed, | |
| 3013 | + 'get_del_code_from_ctxt' does not generate an instruction for deleting the last 'ret' | |
| 3014 | + of the context. Furthermore, an initial 0 has been pushed into the stack by 'start'. | |
| 3015 | + | |
| 3016 | + */ | |
| 3017 | + int d = length(ctxt); | |
| 3018 | + Expr a = new_addr_name(labs_none,0); | |
| 3019 | + Expr before_start = get_before_start_code(ctxt,env); | |
| 3020 | + Expr priority_code = compile_term(third(head),ctxt,env,nil); | |
| 3021 | + Expr delegated_code = compile_term(forth(head),ctxt,env,nil); | |
| 3022 | + Expr virtual_deletions = get_del_code_from_ctxt(ctxt,env); | |
| 3023 | + Expr body_code = compile_term(cdr4(head),ctxt,env,end_code); | |
| 3024 | + | |
| 3025 | + code = mcons3(finish, | |
| 3026 | + cons(label,a), | |
| 3027 | + remove_check_stack(body_code)); | |
| 3028 | + | |
| 3029 | + code = cons(get_del_instr(type_from_interpretation(third(head),env),env),code); /* deleting R */ | |
| 3030 | + /* actually, deleting R is not useful because the type of the datum in R is 'One' */ | |
| 3031 | + assert(car(code) == no_instr); | |
| 3032 | + code = append(virtual_deletions,code); | |
| 3033 | + code = cons(cons(comment,new_string("deleting initial stack content")),code); | |
| 3034 | + code = append(delegated_code,code); | |
| 3035 | + | |
| 3036 | + code = cons(mcons3(startp,new_integer(d),a),code); | |
| 3037 | + code = append(priority_code,code); | |
| 3038 | + code = cons(cons(comment,new_string("computing priority level of new process")),code); | |
| 3039 | + code = append(before_start,code); | |
| 3040 | + code = cons(cons(check_stack,new_integer(stack_needs(body_code))),code); | |
| 3041 | + } | |
| 3042 | + break; | |
| 3043 | + | |
| 3044 | + | |
| 3045 | + | |
| 3046 | + /*---------------------------------------------------------------------------*/ | |
| 3047 | + | |
| 2988 | 3048 | case serialize: |
| 2989 | 3049 | case tempserialize: |
| 2990 | 3050 | { | ... | ... |
anubis_dev/compiler/src/description.text
| ... | ... | @@ -656,7 +656,8 @@ |
| 656 | 656 | (of_type <lc> <type> . <term>) (explicit typing) |
| 657 | 657 | (string <lc> . <string>) (<string> is a Lisp-like string) |
| 658 | 658 | (with <lc> <symbol> <value> . <term>) |
| 659 | - (delegate <lc> <term> . <term>) | |
| 659 | + (delegate <lc> <term> . <term>) (obsoleted by delegatep) | |
| 660 | + (delegatep <lc> <term> <term> . <term>) (delegate (priority) delegated, body) | |
| 660 | 661 | (lambda <lc> <FArgs> . <term>) (|->) |
| 661 | 662 | (rec_lambda <lc> <name> <FArgs> . <term>) (|-f->) |
| 662 | 663 | (app <lc> <term> . <terms>) (applicative term) |
| ... | ... | @@ -743,6 +744,7 @@ |
| 743 | 744 | (with <lc> <symbol> <head> . <head>) |
| 744 | 745 | |
| 745 | 746 | (delegate <lc> <head> . <head>) |
| 747 | + (delegatep <lc> <head> <head> . <head>) | |
| 746 | 748 | (serialize <lc> . <head>) |
| 747 | 749 | (unserialize <lc> <type> . <head>) |
| 748 | 750 | |
| ... | ... | @@ -1438,7 +1440,8 @@ |
| 1438 | 1440 | |
| 1439 | 1441 | *** (2.3.5.8) Starting a new virtual machine. |
| 1440 | 1442 | |
| 1441 | - (start <depth> . <addr>) | |
| 1443 | + (start <depth> . <addr>) (obsoleted by startp) | |
| 1444 | + (startp <priority> <depth> . <addr>) | |
| 1442 | 1445 | |
| 1443 | 1446 | This instruction is generated by the keyword 'delegate' and starts a new virtual |
| 1444 | 1447 | machine. '<depth>' is the number of slots on top of the stack of the old machine which | ... | ... |
anubis_dev/compiler/src/expr.cpp
| ... | ... | @@ -216,6 +216,9 @@ Expr pcons(Expr x, Expr y) |
| 216 | 216 | /* saving an expression in the permanent zone */ |
| 217 | 217 | Expr save(Expr x) |
| 218 | 218 | { |
| 219 | + | |
| 220 | + //debug(x); | |
| 221 | + | |
| 219 | 222 | if (is_tpair(x)) |
| 220 | 223 | { |
| 221 | 224 | if (car(x) == anb_int32) |
| ... | ... | @@ -1155,7 +1158,7 @@ int sprint_tail(char *filep, Expr expr) |
| 1155 | 1158 | |
| 1156 | 1159 | int currently_debugging = 1; |
| 1157 | 1160 | |
| 1158 | -Expr _debug(char *name, Expr expr, char * filename, int line) | |
| 1161 | +Expr _debug(const char *name, Expr expr, char * filename, int line) | |
| 1159 | 1162 | { |
| 1160 | 1163 | if (currently_debugging) |
| 1161 | 1164 | { | ... | ... |
anubis_dev/compiler/src/grammar.y
| ... | ... | @@ -691,7 +691,8 @@ Term: yy__alert { alert_obsolete($1); |
| 691 | 691 | | yy__with yy__tilde yy__equals Term yy__comma WithTerm { $$ = mcons5(with,$3,$2,$4,$6); } |
| 692 | 692 | | yy__checking_every Term yy__milliseconds yy__comma yy__wait_for Term yy__then Term |
| 693 | 693 | { $$ = mcons5(wait_for,$1,$6,$2,$8); } |
| 694 | -| yy__delegate Term yy__comma Term { $$ = mcons4(delegate,$1,$2,$4); } | |
| 694 | +| yy__delegate Term yy__comma Term { $$ = mcons4(delegate,$1,$2,$4); } | |
| 695 | +| yy__delegate yy__lpar Term yy__rpar Term yy__comma Term { $$ = mcons5(delegatep,$1,$3,$5,$7); } | |
| 695 | 696 | | yy__lpar FArgs1 yy__rpar yy__mapsto Term { $$ = mcons4(lambda,$4,$2,$5); } |
| 696 | 697 | | yy__lpar FArgs1 yy__rpar yy__rec_mapsto Term { $$ = mcons5(rec_lambda,$3,$4,$2,$5); } |
| 697 | 698 | | yy__lbrace BEGINLBA yy__end_LBA { $$ = mcons3(byte_array,$1,$3); } | ... | ... |
anubis_dev/compiler/src/interp.c
| ... | ... | @@ -122,6 +122,15 @@ Expr delegate_interpretations (Expr lc, |
| 122 | 122 | Expr env, |
| 123 | 123 | Expr tvs); |
| 124 | 124 | |
| 125 | +Expr delegatep_interpretations (Expr lc, | |
| 126 | + Expr ttype, | |
| 127 | + Expr priority, | |
| 128 | + Expr delegated, | |
| 129 | + Expr body, | |
| 130 | + Expr ctxt, | |
| 131 | + Expr env, | |
| 132 | + Expr tvs); | |
| 133 | + | |
| 125 | 134 | Expr serialize_interpretations (Expr lc, |
| 126 | 135 | int allow_serialize_Opaque, |
| 127 | 136 | Expr ttype, |
| ... | ... | @@ -2109,6 +2118,22 @@ term_interpretations(Expr ttype, /* required type for that term (may contai |
| 2109 | 2118 | env, |
| 2110 | 2119 | tvs); |
| 2111 | 2120 | } |
| 2121 | + break; | |
| 2122 | + | |
| 2123 | + | |
| 2124 | + case delegatep: | |
| 2125 | + { | |
| 2126 | + /* (delegatep <lc> <term> <term> . <term>) */ | |
| 2127 | + term = cdr(term); | |
| 2128 | + result = delegatep_interpretations(car(term), /* lc */ | |
| 2129 | + dummy, | |
| 2130 | + second(term), /* priority */ | |
| 2131 | + third(term), /* delegated */ | |
| 2132 | + cdr3(term), /* body */ | |
| 2133 | + ctxt, | |
| 2134 | + env, | |
| 2135 | + tvs); | |
| 2136 | + } | |
| 2112 | 2137 | break; |
| 2113 | 2138 | |
| 2114 | 2139 | |
| ... | ... | @@ -4591,12 +4616,12 @@ Expr wait_for_interpretations (Expr lc, |
| 4591 | 4616 | |
| 4592 | 4617 | |
| 4593 | 4618 | Expr delegate_interpretations (Expr lc, |
| 4594 | - Expr ttype, | |
| 4595 | - Expr delegated, | |
| 4596 | - Expr body, | |
| 4597 | - Expr ctxt, | |
| 4598 | - Expr env, | |
| 4599 | - Expr tvs) | |
| 4619 | + Expr ttype, | |
| 4620 | + Expr delegated, | |
| 4621 | + Expr body, | |
| 4622 | + Expr ctxt, | |
| 4623 | + Expr env, | |
| 4624 | + Expr tvs) | |
| 4600 | 4625 | { |
| 4601 | 4626 | /* 'delegate u, v' is correct if 'u' has a unique interpretation of type |
| 4602 | 4627 | 'One', and if 'v' may be interpreted. */ |
| ... | ... | @@ -4613,7 +4638,7 @@ Expr delegate_interpretations (Expr lc, |
| 4613 | 4638 | while (consp(aux)) |
| 4614 | 4639 | { |
| 4615 | 4640 | if (type_from_interpretation(car(car(aux)),cdr(car(aux))) == pdstr_One) |
| 4616 | - one_deleg_ints = cons(car(aux),one_deleg_ints); | |
| 4641 | + one_deleg_ints = cons(car(aux),one_deleg_ints); | |
| 4617 | 4642 | aux = cdr(aux); |
| 4618 | 4643 | } |
| 4619 | 4644 | |
| ... | ... | @@ -4656,11 +4681,133 @@ Expr delegate_interpretations (Expr lc, |
| 4656 | 4681 | { |
| 4657 | 4682 | /* each interpretation head is (delegate lc Ideleg . Ibody) */ |
| 4658 | 4683 | result = cons(cons(mcons4(delegate, |
| 4659 | - lc, | |
| 4660 | - car(car(one_deleg_ints)), | |
| 4661 | - car(car(body_ints))), | |
| 4662 | - cdr(car(body_ints))), | |
| 4663 | - result); | |
| 4684 | + lc, | |
| 4685 | + car(car(one_deleg_ints)), | |
| 4686 | + car(car(body_ints))), | |
| 4687 | + cdr(car(body_ints))), | |
| 4688 | + result); | |
| 4689 | + body_ints = cdr(body_ints); | |
| 4690 | + } | |
| 4691 | + return result; | |
| 4692 | +} | |
| 4693 | + | |
| 4694 | + | |
| 4695 | + | |
| 4696 | +Expr delegatep_interpretations (Expr lc, | |
| 4697 | + Expr ttype, | |
| 4698 | + Expr priority, | |
| 4699 | + Expr delegated, | |
| 4700 | + Expr body, | |
| 4701 | + Expr ctxt, | |
| 4702 | + Expr env, | |
| 4703 | + Expr tvs) | |
| 4704 | +{ | |
| 4705 | + /* 'delegate u, v' is correct if 'u' has a unique interpretation of type | |
| 4706 | + 'One', and if 'v' may be interpreted. */ | |
| 4707 | + | |
| 4708 | + Expr priority_ints, word8_priority_ints, deleg_ints, one_deleg_ints, body_ints, aux, result; | |
| 4709 | + | |
| 4710 | + /* interpert priority (its type must be Word8) */ | |
| 4711 | + priority_ints = term_interpretations(dummy,priority,ctxt,env,tvs,0); | |
| 4712 | + if (priority_ints == nil) return nil; | |
| 4713 | + | |
| 4714 | + /* select only those interpretations which are of type 'Word8' */ | |
| 4715 | + aux = priority_ints; | |
| 4716 | + word8_priority_ints = nil; | |
| 4717 | + while (consp(aux)) | |
| 4718 | + { | |
| 4719 | + if (type_from_interpretation(car(car(aux)),cdr(car(aux))) == pdstr_Word8) | |
| 4720 | + word8_priority_ints = cons(car(aux),word8_priority_ints); | |
| 4721 | + aux = cdr(aux); | |
| 4722 | + } | |
| 4723 | + | |
| 4724 | + /* we should have at least one interpretation of type 'Word8' */ | |
| 4725 | + if (word8_priority_ints == nil) | |
| 4726 | + { | |
| 4727 | + if (show_errors) | |
| 4728 | + { | |
| 4729 | + err_line_col(lc,"E123", | |
| 4730 | + msgtext_priority_not_word8[0]); | |
| 4731 | + show_interpretations_types(errfile,priority_ints); | |
| 4732 | + } | |
| 4733 | + return nil; | |
| 4734 | + } | |
| 4735 | + | |
| 4736 | + /* we should not have several interpretations of type 'Word8' */ | |
| 4737 | + if (cdr(word8_priority_ints) != nil) | |
| 4738 | + { | |
| 4739 | + if (show_errors) | |
| 4740 | + { | |
| 4741 | + err_line_col(lc,"E124", | |
| 4742 | + msgtext_priority_ambiguous[0]); | |
| 4743 | + show_simple_ambiguity(errfile,word8_priority_ints); | |
| 4744 | + } | |
| 4745 | + return nil; | |
| 4746 | + } | |
| 4747 | + | |
| 4748 | + /* update 'env' with the environment of the unique interpretation of | |
| 4749 | + the delegated term */ | |
| 4750 | + env = cdr(car(word8_priority_ints)); | |
| 4751 | + | |
| 4752 | + /* interpret delegated (its type must be 'One') */ | |
| 4753 | + deleg_ints = term_interpretations(dummy,delegated,ctxt,env,tvs,0); | |
| 4754 | + if (deleg_ints == nil) return nil; | |
| 4755 | + | |
| 4756 | + /* select only those interpretations which are of type 'One' */ | |
| 4757 | + aux = deleg_ints; | |
| 4758 | + one_deleg_ints = nil; | |
| 4759 | + while (consp(aux)) | |
| 4760 | + { | |
| 4761 | + if (type_from_interpretation(car(car(aux)),cdr(car(aux))) == pdstr_One) | |
| 4762 | + one_deleg_ints = cons(car(aux),one_deleg_ints); | |
| 4763 | + aux = cdr(aux); | |
| 4764 | + } | |
| 4765 | + | |
| 4766 | + /* we should have at least one interpretation of type 'One' */ | |
| 4767 | + if (one_deleg_ints == nil) | |
| 4768 | + { | |
| 4769 | + if (show_errors) | |
| 4770 | + { | |
| 4771 | + err_line_col(lc,"E057", | |
| 4772 | + msgtext_delegated_not_one[0]); | |
| 4773 | + show_interpretations_types(errfile,deleg_ints); | |
| 4774 | + } | |
| 4775 | + return nil; | |
| 4776 | + } | |
| 4777 | + | |
| 4778 | + /* we should not have several interpretations of type 'One' */ | |
| 4779 | + if (cdr(one_deleg_ints) != nil) | |
| 4780 | + { | |
| 4781 | + if (show_errors) | |
| 4782 | + { | |
| 4783 | + err_line_col(lc,"E058", | |
| 4784 | + msgtext_delegated_ambiguous[0]); | |
| 4785 | + show_simple_ambiguity(errfile,one_deleg_ints); | |
| 4786 | + } | |
| 4787 | + return nil; | |
| 4788 | + } | |
| 4789 | + | |
| 4790 | + /* update 'env' with the environment of the unique interpretation of | |
| 4791 | + the delegated term */ | |
| 4792 | + env = cdr(car(one_deleg_ints)); | |
| 4793 | + | |
| 4794 | + /* now, we have to interpret the 'body' term (in the same context) */ | |
| 4795 | + body_ints = term_interpretations(dummy,body,ctxt,env,tvs,0); | |
| 4796 | + if (body_ints == nil) return nil; | |
| 4797 | + | |
| 4798 | + /* finally, we have one interpretation for each interpretation of the | |
| 4799 | + body term */ | |
| 4800 | + result = nil; | |
| 4801 | + while (consp(body_ints)) | |
| 4802 | + { | |
| 4803 | + /* each interpretation head is (delegatep lc Ipriority Ideleg . Ibody) */ | |
| 4804 | + result = cons(cons(mcons5(delegatep, | |
| 4805 | + lc, | |
| 4806 | + car(car(word8_priority_ints)), | |
| 4807 | + car(car(one_deleg_ints)), | |
| 4808 | + car(car(body_ints))), | |
| 4809 | + cdr(car(body_ints))), | |
| 4810 | + result); | |
| 4664 | 4811 | body_ints = cdr(body_ints); |
| 4665 | 4812 | } |
| 4666 | 4813 | return result; |
| ... | ... | @@ -4668,6 +4815,10 @@ Expr delegate_interpretations (Expr lc, |
| 4668 | 4815 | |
| 4669 | 4816 | |
| 4670 | 4817 | |
| 4818 | + | |
| 4819 | + | |
| 4820 | + | |
| 4821 | + | |
| 4671 | 4822 | #ifdef toto |
| 4672 | 4823 | Expr set_interpretations (Expr lc, |
| 4673 | 4824 | Expr ttype, | ... | ... |
anubis_dev/compiler/src/msgtexts.c
| ... | ... | @@ -435,10 +435,21 @@ const char *msgtext_wait_milliseconds_ambiguous[] = |
| 435 | 435 | { " The milliseconds delay after 'wait for' is ambiguous,\n for the following reason:\n" }; |
| 436 | 436 | |
| 437 | 437 | const char *msgtext_delegated_not_one[] = |
| 438 | -{ " The term after 'delegate' is not of\n type 'One'. The types found are:\n" }; | |
| 438 | +{ " The delegated term after 'delegate' is not of type 'One'.\n" | |
| 439 | + " The types found are:\n" | |
| 440 | +}; | |
| 441 | + | |
| 442 | +const char *msgtext_priority_not_word8[] = | |
| 443 | +{ | |
| 444 | + " The priority level after 'delegate' is not of type 'Word8'.\n" | |
| 445 | + " The types found are:\n" | |
| 446 | +}; | |
| 439 | 447 | |
| 440 | 448 | const char *msgtext_delegated_ambiguous[] = |
| 441 | -{ " The term after 'delegate' is ambiguous,\n for the following reason:\n" }; | |
| 449 | +{ " The delegated term after 'delegate' is ambiguous,\n for the following reason:\n" }; | |
| 450 | + | |
| 451 | +const char *msgtext_priority_ambiguous[] = | |
| 452 | +{ " The priority level after 'delegate' is ambiguous,\n for the following reason:\n" }; | |
| 442 | 453 | |
| 443 | 454 | const char *msgtext_select_cond_incompatible_types[] = |
| 444 | 455 | { " In the conditional, the type of the case body\n" | ... | ... |
anubis_dev/compiler/src/optimize.c
| ... | ... | @@ -1048,6 +1048,16 @@ Expr optimize_definition_code(Expr code) |
| 1048 | 1048 | code = optimize_copy_del(code); |
| 1049 | 1049 | } while (changed); |
| 1050 | 1050 | |
| 1051 | + /* drive back del_stack instructions to the end of code */ | |
| 1052 | +#if 0 | |
| 1053 | + if (optimization_flags & opt_flag_drive_back) | |
| 1054 | + do | |
| 1055 | + { | |
| 1056 | + changed = 0; | |
| 1057 | + code = drive_back(code); | |
| 1058 | + } while (changed); | |
| 1059 | +#endif | |
| 1060 | + | |
| 1051 | 1061 | /* groups of instructions optimization */ |
| 1052 | 1062 | #if 1 |
| 1053 | 1063 | if (optimization_flags & opt_flag_grp) | ... | ... |
anubis_dev/compiler/src/typetools.c
| ... | ... | @@ -301,6 +301,10 @@ Expr _type_from_interpretation(Expr head, Expr env) |
| 301 | 301 | result = type_from_interpretation(cdr3(head),env); |
| 302 | 302 | break; |
| 303 | 303 | |
| 304 | + case delegatep: /* (delegate <lc> <head> <head> . <head>) */ | |
| 305 | + result = type_from_interpretation(cdr4(head),env); | |
| 306 | + break; | |
| 307 | + | |
| 304 | 308 | /* |
| 305 | 309 | case omega_true: |
| 306 | 310 | case omega_false: | ... | ... |
anubis_dev/compiler/src/vminstr.c
| ... | ... | @@ -292,6 +292,7 @@ int instruction_size(Expr instr, int offset) |
| 292 | 292 | case mvar_slots_del_mixed: |
| 293 | 293 | case select_index_indirect: |
| 294 | 294 | case start: |
| 295 | + case startp: | |
| 295 | 296 | case type_mixed: |
| 296 | 297 | case indirect_type_mixed: |
| 297 | 298 | case del_stack_struct_ptr: |
| ... | ... | @@ -1482,6 +1483,13 @@ void translate_instruction(U8 *code_addr, |
| 1482 | 1483 | *ptr += sizeof(U32); |
| 1483 | 1484 | break; |
| 1484 | 1485 | |
| 1486 | + case startp: /* (start <depth> . <addr>) */ | |
| 1487 | + *((*ptr)++) = i_startp; | |
| 1488 | + *((*ptr)++) = integer_value(second(instr)); | |
| 1489 | + *(((U32 *)(*ptr))) = offsets[integer_value(cdr2(instr))]; | |
| 1490 | + *ptr += sizeof(U32); | |
| 1491 | + break; | |
| 1492 | + | |
| 1485 | 1493 | case _switch: /* (switch a1 ... ak) --> |
| 1486 | 1494 | i_switch k a1 ... ak */ |
| 1487 | 1495 | { | ... | ... |
anubis_dev/include/bytecode.h
anubis_dev/include/minver.h
anubis_dev/library/web/torture_server.anubis
| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | |
| 7 | 7 | |
| 8 | 8 | |
| 9 | - | |
| 9 | +read tools/time.anubis | |
| 10 | 10 | read web/http_get.anubis |
| 11 | 11 | |
| 12 | 12 | |
| ... | ... | @@ -19,6 +19,7 @@ define One |
| 19 | 19 | ) = |
| 20 | 20 | print(to_decimal(n)+"/"+to_decimal(i)+" "); |
| 21 | 21 | forget(http_get(addr,"/",[],[])); |
| 22 | + //sleep(5000); | |
| 22 | 23 | ask_pages(addr,n,i+1). |
| 23 | 24 | |
| 24 | 25 | |
| ... | ... | @@ -29,7 +30,7 @@ global define One |
| 29 | 30 | ) = |
| 30 | 31 | with addr = if args is { [] then "127.0.0.1" , [ h . _] then h}, |
| 31 | 32 | forget( |
| 32 | - delegate ask_pages(addr,0,0), | |
| 33 | + delegate (247) ask_pages(addr,0,0), | |
| 33 | 34 | delegate ask_pages(addr,1,0), |
| 34 | 35 | delegate ask_pages(addr,2,0), |
| 35 | 36 | delegate ask_pages(addr,3,0), | ... | ... |
anubis_dev/manuals/en/Anubis-doc-1-13.pdf
No preview for this file type
anubis_dev/manuals/en/Anubis-doc-1-13.tex
| ... | ... | @@ -598,7 +598,7 @@ |
| 598 | 598 | {\sl Alain Prouté}\\ |
| 599 | 599 | \ \\ |
| 600 | 600 | Last revision of this text~: \today\\ |
| 601 | -Refers to version~: 1.13 | |
| 601 | +Refers to version 1.14 and subsequent versions | |
| 602 | 602 | \end{center} |
| 603 | 603 | |
| 604 | 604 | |
| ... | ... | @@ -892,7 +892,25 @@ is && with |
| 892 | 892 | \end{liste} |
| 893 | 893 | |
| 894 | 894 | |
| 895 | -\section{The typing system} | |
| 895 | + | |
| 896 | +\subsection{Syntactic considerations} | |
| 897 | + | |
| 898 | + | |
| 899 | +% | |
| 900 | +% | |
| 901 | +% | |
| 902 | +% | |
| 903 | +% | |
| 904 | +% | |
| 905 | +% | |
| 906 | +% | |
| 907 | +% | |
| 908 | +% | |
| 909 | +% | |
| 910 | +% | |
| 911 | +% | |
| 912 | +% | |
| 913 | +\section{The system of types} | |
| 896 | 914 | The typing system is the very heart of the Anubis programming paradigm. The safety of the code |
| 897 | 915 | you produce is mainly a consequence of the design of the typing system, just as the soundness of a |
| 898 | 916 | bridge depends on the design of its piers. |
| ... | ... | @@ -964,6 +982,25 @@ see below. |
| 964 | 982 | % |
| 965 | 983 | % |
| 966 | 984 | % |
| 985 | +\subsection{Primitive types} | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | +% | |
| 990 | +% | |
| 991 | +% | |
| 992 | +% | |
| 993 | +% | |
| 994 | +% | |
| 995 | +% | |
| 996 | +% | |
| 997 | +% | |
| 998 | +% | |
| 999 | +% | |
| 1000 | +% | |
| 1001 | +% | |
| 1002 | +% | |
| 1003 | +% | |
| 967 | 1004 | \subsection{Defining named types} |
| 968 | 1005 | We now enter into the details of the definition of a new data type (named type) as in the example above |
| 969 | 1006 | (first tool). |
| ... | ... | @@ -985,7 +1022,7 @@ We now enter into the details of the definition of a new data type (named type) |
| 985 | 1022 | % |
| 986 | 1023 | % |
| 987 | 1024 | % |
| 988 | -\subsection{Using functional types} | |
| 1025 | +\subsection{Functional types} | |
| 989 | 1026 | |
| 990 | 1027 | |
| 991 | 1028 | % |
| ... | ... | @@ -1189,6 +1226,132 @@ a micro-context. Such a pair is generally called a ``closure'' in computer scien |
| 1189 | 1226 | \subsection{Schemas}\mylabel{sec:schemas} |
| 1190 | 1227 | |
| 1191 | 1228 | |
| 1229 | + | |
| 1230 | +\section{Objects} | |
| 1231 | + | |
| 1232 | + | |
| 1233 | +\subsection{Types versus classes and data versus objects} | |
| 1234 | +Object oriented programming has introduced the notions of ``object'' and ``class'', which are often | |
| 1235 | +thought of as generalizations of the notions of ``datum'' and ``type''. I don't agree with this point | |
| 1236 | +of view because data and objects have very different behaviors. In particular, I think that the | |
| 1237 | +``all object'' paradigm, adopted by several computer languages, is not at all a good idea, because | |
| 1238 | +objects are much more difficult to manipulate than data. Doing so puts on data an unnecessary burden. | |
| 1239 | +Of course, if you don't perceive the difference between an object and a datum, the above discussion | |
| 1240 | +is probably meaningless for you. In any case, I discuss this difference below. | |
| 1241 | + | |
| 1242 | +First of all, let's take a real life example. Consider the following two ``things''~: (1) a number (for example, | |
| 1243 | +the number $\pi=3,1415\dots$), and (2) a chair~: | |
| 1244 | +\begin{center} | |
| 1245 | +\includegraphics[width=80mm]{pi_chair.png} | |
| 1246 | +\end{center} | |
| 1247 | +It should be obvious that these two ``things'' don't have the same behavior. For example, you can burn | |
| 1248 | +the chair, but it is very unlikely that you are able to burn the number $\pi$. Maybe, you can burn | |
| 1249 | +a piece of paper with $\pi$ printed on it, but you cannot burn the number itself. Unlike the chair, | |
| 1250 | +$\pi$ is undestroyable. This is a first difference, but there are many others. | |
| 1251 | + | |
| 1252 | +For example, you can have two ``identical'' chairs, more precisely two ``copies'' of the same chair, but | |
| 1253 | +what would it mean to have two copies of the number $\pi$~? I assure you that mathematicians never consider | |
| 1254 | +copies of the number $\pi$. They never say ``a number $\pi$'', but always ``the number $\pi$'', which is therefore | |
| 1255 | +unique, unlike the chair. | |
| 1256 | + | |
| 1257 | +As another example, it is clear that the chair shown above was made at some time in the past. It has | |
| 1258 | +a ``birth date''. Dou you thing that the number $\pi$ has a birth date~? For sure, there is a date (that | |
| 1259 | +we are unable to determine) at which this number was discovered on the planet earth. But the number $\pi$ | |
| 1260 | + already existed before this date, and maybe was discovered earlier on another planet. | |
| 1261 | + | |
| 1262 | +As a conclusion regarding this example, we will say that {\sl the chair is an object}, and that | |
| 1263 | +{\sl the number $\pi$ is not an object}. | |
| 1264 | + | |
| 1265 | +Now, let's take an example more interesting for programmers. Consider again a number (say a 32 bits number, | |
| 1266 | +of type \code{Word32} in Anubis), and a network connection (of type \code{RWStream} in Anubis). | |
| 1267 | +Like the chair, a connection has a birth date, since in order to have a connection we need to ``open'' | |
| 1268 | +a connection. The time at which we open the connection is its birth date. You can also destroy (burn~!) the | |
| 1269 | +connection just by ``closing'' it. | |
| 1270 | + | |
| 1271 | + | |
| 1272 | + | |
| 1273 | +\subsection{Dynamic variables} | |
| 1274 | +Anubis has a special kind of objects called ``dynamic variables''. In programming, the word ``variable'' | |
| 1275 | +generally represents some place in memory where a datum of a certain type can be stored. For example, | |
| 1276 | +in the language C, you can write~: | |
| 1277 | +\begin{verbatim} | |
| 1278 | +int i; | |
| 1279 | +\end{verbatim} | |
| 1280 | +which means that you want some place able to contain an integer (of type {\tt int} in this case). Notice | |
| 1281 | +that in the above example, this place is considered as ``empty'' since, I did not give it an ``initial value'', | |
| 1282 | +but the important thing is that you can put a value (an ``int'') into it, and that you can also change this value at will | |
| 1283 | +during the execution of your program. | |
| 1284 | +Notice that {\tt i} is called a ``variable'' just because its content may vary. | |
| 1285 | + | |
| 1286 | +In the language C, and many other languages since the paradigm of C has spread almost everywhere in programming languages, | |
| 1287 | +such a variable is either ``local'' or ``global'' depending on the fact that it is declared within the body | |
| 1288 | +of a function or not. | |
| 1289 | +In Anubis, you don't have local variables of the above sort. This is also linked to the fact that Anubis has no | |
| 1290 | +notion of loop (at least explicitely). See the discussion on functions for more details on this question. | |
| 1291 | +Anubis also does not have global variables in the above sens. There are global notions in Anubis, but none deserves the | |
| 1292 | +name of ``variable''. | |
| 1293 | + | |
| 1294 | +Before going further, remark that a variable in the above sens (i.e. a place whose content may change during execution) | |
| 1295 | +cannot be a datum, but is necessarily an object. Indeed, you can have two variables, for example declared in C like this~: | |
| 1296 | +\begin{verbatim} | |
| 1297 | +int i = 3; | |
| 1298 | +int j = 3; | |
| 1299 | +\end{verbatim} | |
| 1300 | +which are in some sens ``identical'', because they are of the same type and contain the same number. Nevertheless, you know that they | |
| 1301 | +are not identical, for example because a confusion between them is most probably a bug. These two variables are like two chairs of the same model. | |
| 1302 | +They are at the same time ``identical'' (same type, same content), and distinct because they are not at the same place in memory, | |
| 1303 | +just like two ``identical'' chairs cannot be at the same place in your dinning room (according to Pauli's principle, since they are | |
| 1304 | +made of fermions). | |
| 1305 | + | |
| 1306 | +Probably, a variable like {\tt i} above could better be called a `container'', because its only | |
| 1307 | +purpose is to ``contain'' something. However (again~!), what should better be called a container is not {\tt i} | |
| 1308 | +but {\tt \&i}, the ``address'' of {\tt i}. Indeed, in the language C, {\tt i} does not represent the place where | |
| 1309 | +the number is stored, but the very number stored in this place, i.e. only the content of the container. | |
| 1310 | +Nevertheless, this is still {\tt i} which is called a ``variable'' and not {\tt \&i}, probably because what may vary | |
| 1311 | +is not the container itself but its content. | |
| 1312 | + | |
| 1313 | +As a conclusion of the above discussion, we can say for sure that the ``container'' (aka. the ``variable'') is an object. | |
| 1314 | + | |
| 1315 | +Now, comming back to Anubis, we have the notion of ``dynamic variable'', which designates a container (hence an object), | |
| 1316 | +which is at the same time ``variable'' (its content may change during execution) and ``dynamic'' (it can be created/destroyed | |
| 1317 | +during execution). | |
| 1318 | + | |
| 1319 | +The purpose of dynamic variables in Anubis is not to be used as storage places for making abstract computations. In Anubis | |
| 1320 | +(and in functionnal languages in general), abstract computations must better avoid the use of any object. Avoiding the use | |
| 1321 | +of any object entails that the program is deterministic. This has the important consequence that it is more easy to understand, | |
| 1322 | +and consequently less error prone. | |
| 1323 | + | |
| 1324 | +The main uses of dynamic variables is (1) the creation of objects, (2) the communication between Anubis processes. | |
| 1325 | +Below we first explain the syntax and semantics of dynamic variables, and in the subsequent sections we give examples | |
| 1326 | +of their uses. | |
| 1327 | + | |
| 1328 | +\subsubsection{Syntax and semantics} | |
| 1329 | +A dynamic variable able to contain a datum of type \code{T} is itself of class \code{Var(T)}. In order to create | |
| 1330 | +a dynamic variable of class \code{Var(T)}, you must provide an initial content (of type \code{T}). The command~: | |
| 1331 | +\begin{center} | |
| 1332 | +\code{var(\sconcept{term})} | |
| 1333 | +\end{center} | |
| 1334 | +(where \sconcept{term} is of type \code{T}) creates such a dynamic variable with initial content \sconcept{term}. | |
| 1335 | +Thus, a dynamic variable is never empty, so that ``reading'' its content cannot produce an error. | |
| 1336 | + | |
| 1337 | +If \code{v} is a dynamic variable of class \code{Var(T)}, \code{*v} (which is of type \code{T}) represents the | |
| 1338 | +content of the variable, and if you want to change the value of the variable, use the command~: | |
| 1339 | +\begin{center} | |
| 1340 | +\code{v <- \sconcept{term}} | |
| 1341 | +\end{center} | |
| 1342 | +where \sconcept{term} is the new content of \code{v}. The expression \code{v <- \sconcept{term}} is of type \code{One}, | |
| 1343 | +so that it can be put in front of a semi-colon. | |
| 1344 | + | |
| 1345 | + | |
| 1346 | +\subsubsection{Creating objects} | |
| 1347 | + | |
| 1348 | +\subsubsection{Communication between Anubis processes} | |
| 1349 | + | |
| 1350 | +\subsubsection{Functions and encapsulation} | |
| 1351 | + | |
| 1352 | + | |
| 1353 | + | |
| 1354 | + | |
| 1192 | 1355 | % |
| 1193 | 1356 | % |
| 1194 | 1357 | % |
| ... | ... | @@ -1293,7 +1456,24 @@ by something needing the body of their definition, a macro or an inline function |
| 1293 | 1456 | it is defined (hence can also not be recursive). Unlike ordinary functions, declaring it is not enough for using~it. |
| 1294 | 1457 | |
| 1295 | 1458 | |
| 1459 | +\subsection{Serializing/unserializing data} | |
| 1460 | + | |
| 1296 | 1461 | |
| 1462 | + | |
| 1463 | +% | |
| 1464 | +% | |
| 1465 | +% | |
| 1466 | +% | |
| 1467 | +% | |
| 1468 | +% | |
| 1469 | +% | |
| 1470 | +% | |
| 1471 | +% | |
| 1472 | +% | |
| 1473 | +% | |
| 1474 | +% | |
| 1475 | +% | |
| 1476 | +% | |
| 1297 | 1477 | \subsection{Primary and secondary modules (\code{load\_adm})} |
| 1298 | 1478 | Each paragraph beginning by the keyword \code{global} produces a so-called ``module'', precisely, |
| 1299 | 1479 | an ``Anubis dynamic module'' (aka ``adm'') which is stored by the compiler into a file with |
| ... | ... | @@ -1358,7 +1538,7 @@ it is possible to load a secondary module. It is of course possible to make this |
| 1358 | 1538 | as shown by the web server defined in \code{library/web/dynamic\_http\_server.anubis}. This program |
| 1359 | 1539 | looks for secondary modules whose name matches the mask \code{*\_web\_site.adm}, and automatically |
| 1360 | 1540 | loads them, or reloads them when they are recompiled, thus enabling to update the code of a web site |
| 1361 | -without stopping the web server. Even more, the new version and the previous version can work conccurently | |
| 1541 | +without stopping the web server. Even more, the new version and the previous version can work concurrently | |
| 1362 | 1542 | if a request answered by the previous version is still being serviced while the new version is already loaded |
| 1363 | 1543 | and servicing another client. |
| 1364 | 1544 | |
| ... | ... | @@ -1521,48 +1701,54 @@ several so-called ``Anubis processes'' (``process'' for short). These processes |
| 1521 | 1701 | of the underlying operating system (Unix, Windows, \dots). |
| 1522 | 1702 | |
| 1523 | 1703 | \subsubsection{Features and caveats} |
| 1704 | +Anubis is multitasking because when I started to develop it around the year 2000, I had the idea to try to | |
| 1705 | +construct a small operating system (just as an exercice for fun). I abandonned this idea later (maybe not for ever), | |
| 1706 | +but because of this, Anubis has a scheduler | |
| 1707 | +and is able to launch many processes within a single process of the host system. | |
| 1708 | + | |
| 1709 | +This has advantages and disadvantages. The main avantage is that launching an Anubis process requires far | |
| 1710 | +less memory than launching a process of the underlying system. This is mainly because all Anubis processes | |
| 1711 | +running in a single instance of \code{anbexec} share the same memory heap. Of course, each process has | |
| 1712 | +its own stack (which is small when the process is created but which can grown automatically), but | |
| 1713 | +all data which are not directly in the stack are in the common pool of memory. In particular, Anubis | |
| 1714 | +processes can share dynamic variables that they use as ``mailboxes'' for communicating. | |
| 1715 | + | |
| 1716 | +This design allows for example the HTTP server defined in \code{library/web} to serve many clients | |
| 1717 | +simultaneously while still be running in a single thread of the host system. This is good for both speed | |
| 1718 | +and memory usage. | |
| 1719 | + | |
| 1720 | +The main disadvantage is that a single instance of \code{anbexec} cannot use several physical processors. But it | |
| 1721 | +is still possible to launch several instances of \code{anbexec} collaborating through local connections and | |
| 1722 | +run by different physical processors. Of course, this needs a special conception of the whole project. It is | |
| 1723 | +not impossible that in the future Anubis is enhanced for being able to use several physical processors | |
| 1724 | +transparently. | |
| 1725 | + | |
| 1726 | + | |
| 1727 | + | |
| 1524 | 1728 | |
| 1525 | 1729 | \subsubsection{Syntax and semantics} |
| 1526 | 1730 | In order to launch an Anubis process, use the keyword \code{delegate}. There are two distinct syntaxes |
| 1527 | 1731 | for delegate~: |
| 1528 | 1732 | \begin{dcode} |
| 1529 | - delegate <term>, <term> // first form | |
| 1530 | - delegate (<term>) <term> // second form | |
| 1733 | +\hs delegate \sconcept{term}, \sconcept{term}\\ | |
| 1734 | +\hs delegate (\sconcept{term}) \sconcept{term}, \sconcept{term} | |
| 1531 | 1735 | \end{dcode} |
| 1532 | -with distinct semantics. | |
| 1533 | -\begin{liste} | |
| 1534 | -\item First form~: Execution of \code{delegate a, b} works as follows~: | |
| 1736 | +The execution of \code{delegate a, b} works as follows~: | |
| 1535 | 1737 | \begin{liste} |
| 1536 | - \item (1) a new Anubis process with priority 0 (background process) is created, | |
| 1537 | - \item (2) the term \code{a}, which must be of type \code{One}, is executed by this new process, | |
| 1738 | + \item (1) a new Anubis process with the same priority level as the current process is created, | |
| 1739 | + \item (2) the term \code{a} (which must be of type \code{One}) is executed by this new process, | |
| 1538 | 1740 | \item (3) the current process executes \code{b}, |
| 1539 | 1741 | \item (4) the value returned by the whole expression \code{delegate a, b} is the value of~\code{b}. |
| 1540 | 1742 | \end{liste} |
| 1541 | - | |
| 1542 | -\item Second form~: Execution of \code{delegate (p) a} works as follows~: | |
| 1543 | - \begin{liste} | |
| 1544 | - \item (1) a new Anubis process is created with priority level \code{p} (of type \code{Word8}), | |
| 1545 | - \item (2) the term \code{a}, which must be of type \code{One}, is executed by this new process, | |
| 1546 | - \item (3) the whole expression \code{delegate (p) a} returns immediately a datum of | |
| 1547 | - type \code{Process}, which identifies the new process. | |
| 1548 | - \end{liste} | |
| 1549 | -\end{liste} | |
| 1550 | -Remark that \code{delegate a, b} is equivalent to \code{forget(delegate (0) a); b}. | |
| 1551 | - | |
| 1552 | -Of course, the second form is more powerful than the first one, but the first one is easier to use if | |
| 1553 | -you don't need to control the priority of processes. Normally, you don't mix boths forms of \code{delegate} | |
| 1554 | -in the same project. | |
| 1555 | - | |
| 1556 | -\code{Process} is an opaque type. However, there are functions for manipulating processes. In particular, | |
| 1557 | -it is possible to change the priority level of a process during its execution. | |
| 1558 | - | |
| 1743 | +The execution of \code{delegate (p) a, b} works in the same way except that the priority level of | |
| 1744 | +the new process is the minimum of the priority level of the current process and of the value of \code{p} | |
| 1745 | +(which is of type \code{Word8}). | |
| 1559 | 1746 | |
| 1560 | 1747 | |
| 1561 | 1748 | \subsubsection{Priority levels} |
| 1562 | 1749 | The priority level of an Anubis process is a datum of type \code{Word8}, i.e. an integer whose value ranges |
| 1563 | -from 0 to 255 (so, considered as positive or zero). Using the second form of \code{delegate}, you can set the priority of a process when it is created. | |
| 1564 | -This priority can later be changed dynamically (i.e. during execution of the process), but be careful about that because | |
| 1565 | -changing the priority of a process during execution can dramatically affect other processes. | |
| 1750 | +from 0 to 255 (so, considered as positive or zero). Using the second form of \code{delegate}, you can set | |
| 1751 | +the priority of a process when it is created. | |
| 1566 | 1752 | |
| 1567 | 1753 | The scheduler takes priority levels into account in the following manner. |
| 1568 | 1754 | |
| ... | ... | @@ -1575,85 +1761,41 @@ by the event puts itself back immediately into a sleeping state. |
| 1575 | 1761 | This said, we are now concerned only by running processes. Each running process is run with |
| 1576 | 1762 | a ``credit'' computed by the scheduler. This credit is the maximal number of virtual machine |
| 1577 | 1763 | instructions the process is allowed to execute before it must give up. The credit cannot be more |
| 1578 | -than a given fixed value (which defaults to 500, but which can be changed using the option \code{-\sh-credit} with \code{anbexec}). | |
| 1764 | +than a given fixed value (which defaults to 500, but which can be changed using the option \code{-\sh-credit} when | |
| 1765 | +launching \code{anbexec}). | |
| 1579 | 1766 | |
| 1580 | 1767 | The credit for running a process is computed as follows (at each passage into the chain of processes)~: |
| 1581 | 1768 | \begin{liste} |
| 1582 | 1769 | \item (1) the scheduler computes the maximum $M$ of the priority levels of all running processes, |
| 1583 | -\item (2) if the priority level of a process is less than or equal to $M-10$, it is not run, | |
| 1584 | -\item (3) if the priority level $L$ of a process is between $M-9$ (included) and $M$ (included), it is run with a | |
| 1585 | -credit of $D(1 - \frac{M-L}{10})$, where $D$ is the default (maximal) credit. | |
| 1770 | +\item (2) if the priority level of a process is less than or equal to $M-16$, it is not run, | |
| 1771 | +\item (3) if the priority level $L$ of a process is between $M-15$ (included) and $M$ (included), it is run with a | |
| 1772 | +credit of $D(1 - \frac{M-L}{16})$, where $D$ is the default (maximal) credit. | |
| 1586 | 1773 | \end{liste} |
| 1587 | 1774 | |
| 1588 | 1775 | Examples~: |
| 1589 | 1776 | \begin{liste} |
| 1590 | -\item We have two processes $A$ and $B$. | |
| 1777 | +\item We have two processes $A$ and $B$, then~: | |
| 1591 | 1778 | \begin{liste} |
| 1592 | - \item If $A$ has priority 50, and $B$ has priority $40$, $B$ must wait that $A$ is sleeping | |
| 1593 | - for running. | |
| 1594 | - \item If $A$ has priority 50 and $B$ has priority $45$, $B$ runs conccurently with $A$, but with half the credit of $A$ (i.e. | |
| 1595 | - $A$ runs twice faster than $B$). | |
| 1596 | - \item If $A$ has priority 50 and $B$ has priority $49$, $B$ runs ten percent slower than $A$. | |
| 1779 | + \item If $A$ has priority $50$, and $B$ has priority $34$ or less, $B$ must wait that $A$ is sleeping | |
| 1780 | + for being allowed to run. | |
| 1781 | + \item If $A$ has priority $50$ and $B$ has priority $42$, $B$ runs concurrently with $A$, but with half the credit of $A$ (i.e. | |
| 1782 | + $A$ runs twice ``faster'' than $B$). | |
| 1783 | + \item If $A$ has priority $50$ and $B$ has priority $49$, $B$ runs $6,25$ percent slower than $A$. | |
| 1597 | 1784 | \end{liste} |
| 1598 | -\item We have several processes $A_1,\dots,A_k$ with priority level 100, and several processes $B_1,\dots,B_n$ with priority | |
| 1599 | - level 20. No $B$ process is running if at least one $A$ process is running. $B$ processes share the computation power | |
| 1600 | - if no $A$ process is running. | |
| 1785 | +\item We have several processes $A_1,\dots,A_k$ with priority level $100$, and several processes $B_1,\dots,B_n$ with priority | |
| 1786 | + level $50$. No $B$ process is running if at least one $A$ process is running. $B$ processes share the computation power | |
| 1787 | + when no $A$ process is running. | |
| 1601 | 1788 | \item We can imagine a web site with absolutely prioritary processes (for administration), client processes (servicing web pages), |
| 1602 | - and background task processes. The priorities could be set like this~: 20 for administration, 10 for clients, and 0 for the | |
| 1603 | - background. You can also imagine to put some administration task at the level 25. | |
| 1789 | + and background task processes. The priorities could be set like this~: 50 for administration, 30 for clients, and 0 for the | |
| 1790 | + background. | |
| 1604 | 1791 | \end{liste} |
| 1792 | +When anbexec starts, it runs a single process (the father of all processes). It has priority level~$255$. | |
| 1605 | 1793 | |
| 1606 | -When anbexec starts, it runs a single process (the father of all processes). It has priority 255, and you can change this priority | |
| 1607 | -at the beginning of your program if needed. | |
| 1608 | 1794 | |
| 1609 | - | |
| 1610 | -% | |
| 1611 | -% | |
| 1612 | -% | |
| 1613 | -% | |
| 1614 | -% | |
| 1615 | -% | |
| 1616 | -% | |
| 1617 | -% | |
| 1618 | -% | |
| 1619 | -% | |
| 1620 | -% | |
| 1621 | -\subsubsection{Changing the priority level of a process} | |
| 1622 | -In order to change the priority level of a process, you need to be allowed to do so. The rules are~: | |
| 1623 | -\begin{liste} | |
| 1624 | -\item (1) A process can never have a priority level greater than its original priority level (the level it has when | |
| 1625 | - it was launched). | |
| 1626 | -\item (2) A process cannot launch a process with a priority level higher than its own priority level. | |
| 1627 | -\item (3) A process can change its own priority level. | |
| 1628 | -\item (4) A process having access to a datum of type \code{Process} can change the priority level of the process | |
| 1629 | - represented by this datum. | |
| 1630 | -\end{liste} | |
| 1631 | -Remark that the only possibility to obtain a datum of type \code{Process} is to launch a process with \code{delegate}, | |
| 1632 | -or to get it through the following tool (defined in \code{predefined.anubis})~: | |
| 1633 | -{\color{darkblue} | |
| 1634 | -\begin{verbatim} | |
| 1635 | -public define Process my_process. | |
| 1636 | -\end{verbatim} | |
| 1637 | -} | |
| 1638 | -If a process executes \code{my\_process}, it gets its own process identifier. | |
| 1639 | 1795 | |
| 1640 | -Getting and setting the priority level of a process is achieved by~: | |
| 1641 | -{\color{darkblue} | |
| 1642 | -\begin{verbatim} | |
| 1643 | -public define Word8 priority (Process p). | |
| 1644 | -public define One set_priority (Process p, Word8 level). | |
| 1645 | -\end{verbatim} | |
| 1646 | -} | |
| 1796 | +\section{Anubis internals} | |
| 1647 | 1797 | |
| 1648 | -For example, if a process wants at some time to run in the background, it can execute~: | |
| 1649 | -\begin{center} | |
| 1650 | -\code{set\_priority(my\_process,0)} | |
| 1651 | -\end{center} | |
| 1652 | -If later it needs to come back to its original priority level, it can execute~: | |
| 1653 | -\begin{center} | |
| 1654 | -\code{set\_priority(my\_process,255)} | |
| 1655 | -\end{center} | |
| 1656 | -The function \code{set\_priority} will put its priority level at its original value (which may be different from~255). | |
| 1798 | +\subsection{The garbage-collector} | |
| 1657 | 1799 | |
| 1658 | 1800 | |
| 1659 | 1801 | ... | ... |
anubis_dev/vm/src/AnubisProcess.cpp
| ... | ... | @@ -71,9 +71,13 @@ AnubisProcess::~AnubisProcess(void) |
| 71 | 71 | } |
| 72 | 72 | |
| 73 | 73 | //int AnubisProcess::Create(int starting_point, U8 *byte_code, U32 code_size, AnubisAllocator *allocator) |
| 74 | -int AnubisProcess::Create(U8 * starting_IP, AnubisAllocator *allocator) | |
| 74 | +int AnubisProcess::Create(U8 * starting_IP, U8 priority, AnubisAllocator *allocator) | |
| 75 | 75 | { |
| 76 | 76 | /* retuns -1 if no machine available, the machine id otherwise. */ |
| 77 | + | |
| 78 | + m_priority = priority; | |
| 79 | + | |
| 80 | + //printf("created process with priority %d\n",m_priority); fflush(stdout); | |
| 77 | 81 | |
| 78 | 82 | /* a machine has been found */ |
| 79 | 83 | /* give a stack to the machine */ |
| ... | ... | @@ -328,14 +332,14 @@ AnubisProcessList::AnubisProcessList() : |
| 328 | 332 | } |
| 329 | 333 | |
| 330 | 334 | //AnubisProcess * AnubisProcessList::CreateAnubisProcess(U32 starting_point, U8 *byte_code, U32 code_size, CM::AnubisAllocator * allocator) |
| 331 | -AnubisProcess * AnubisProcessList::CreateAnubisProcess(U8 * starting_IP, CM::AnubisAllocator * allocator) | |
| 335 | +AnubisProcess * AnubisProcessList::CreateAnubisProcess(U8 * starting_IP, U8 priority, CM::AnubisAllocator * allocator) | |
| 332 | 336 | { |
| 333 | 337 | AnubisProcess * processItem = new AnubisProcess(); |
| 334 | 338 | int pResult; //result status of the create |
| 335 | 339 | |
| 336 | 340 | if (processItem) |
| 337 | 341 | { |
| 338 | - pResult = processItem->Create(starting_IP, allocator); | |
| 342 | + pResult = processItem->Create(starting_IP, priority, allocator); | |
| 339 | 343 | if (pResult >= 0) |
| 340 | 344 | { |
| 341 | 345 | AddItem(processItem); | ... | ... |
anubis_dev/vm/src/AnubisProcess.h
| ... | ... | @@ -60,7 +60,7 @@ class AnubisProcess |
| 60 | 60 | * @param allocator |
| 61 | 61 | * @return Return the process id of new created process, otherwise -1 for error |
| 62 | 62 | */ |
| 63 | - int Create(U8 * starting_IP, AnubisAllocator *allocator); | |
| 63 | + int Create(U8 * starting_IP, U8 priority, AnubisAllocator *allocator); | |
| 64 | 64 | |
| 65 | 65 | /** |
| 66 | 66 | * Set the pid of the process. usually is the process list who decide the pid of the |
| ... | ... | @@ -121,7 +121,7 @@ class AnubisProcess |
| 121 | 121 | protected: |
| 122 | 122 | private: |
| 123 | 123 | U32 m_pid; /* process unique id */ |
| 124 | - anbStatus m_status; /* current status of virtual machine */ | |
| 124 | + anbStatus m_status; /* current status of this process */ | |
| 125 | 125 | U32 m_work_sort; /* what it is currently doing */ |
| 126 | 126 | int m_steps; /* must be signed (((m_steps--) <= 0) in 'vm.cpp') */ |
| 127 | 127 | U32 m_R; /* main register of the machine */ |
| ... | ... | @@ -130,9 +130,9 @@ class AnubisProcess |
| 130 | 130 | //U32 m_starting_point; /* keep trace of starting point for debugging purpose.*/ |
| 131 | 131 | U8* m_IP; /* instruction pointer */ |
| 132 | 132 | U8* m_previous_IP; /* previous value of instruction pointer */ |
| 133 | - U32 * m_SP_begin; /* address of machine's stack */ | |
| 133 | + U32 * m_SP_begin; /* address of process stack */ | |
| 134 | 134 | U32 * m_SP; /* stack pointer */ |
| 135 | - U32 * m_SP_end; /* end of machine's stack */ | |
| 135 | + U32 * m_SP_end; /* end of process stack */ | |
| 136 | 136 | /* the two fields below droped since version 1.13. They are incompatible with the loading |
| 137 | 137 | of several modules, because the same process may execute code from different modules. |
| 138 | 138 | (the same is true of 'm_starting_point' above) */ |
| ... | ... | @@ -154,7 +154,7 @@ class AnubisProcess |
| 154 | 154 | // U32 m_locked_files_stack_size; /* current size of locked files stack */ |
| 155 | 155 | // U32 m_locked_files_SP; /* locked files stack pointer */ |
| 156 | 156 | // U32 * m_locked_files; /* stack of locked files (vm strings) */ |
| 157 | - U8 m_priority; //priority of the process | |
| 157 | + U8 m_priority; // current priority of the process | |
| 158 | 158 | #ifdef instruction_count |
| 159 | 159 | U32 m_i_count[256]; /* one counter for each instruction */ |
| 160 | 160 | #endif |
| ... | ... | @@ -290,7 +290,7 @@ class AnubisProcessList : public List |
| 290 | 290 | static AnubisProcessList* GetInstance(); |
| 291 | 291 | AnubisProcess * GetProcessAt(U32); |
| 292 | 292 | AnubisProcess * GetProcessByID(U32); |
| 293 | - AnubisProcess * CreateAnubisProcess(U8 * starting_IP, AnubisAllocator* allocator); | |
| 293 | + AnubisProcess * CreateAnubisProcess(U8 * starting_IP, U8 priority, AnubisAllocator* allocator); | |
| 294 | 294 | void DeleteProcess(U32 pid); |
| 295 | 295 | AnubisProcess * GetRunningProcess() const { return _runningProcess; } |
| 296 | 296 | void SetRunningProcess(AnubisProcess * current) { _runningProcess = current; } | ... | ... |
anubis_dev/vm/src/anbexec.cpp
| ... | ... | @@ -713,8 +713,62 @@ static void calc_load(U32 ticks, U32 active_tasks /* fixed-point */, bigtime_t * |
| 713 | 713 | } |
| 714 | 714 | } |
| 715 | 715 | |
| 716 | +/* Computing the maximum of the priority levels of all running (non sleeping) machines */ | |
| 717 | +static U8 max_priority_of_runnings(void) | |
| 718 | +{ | |
| 719 | + U32 i; | |
| 720 | + U8 result = 0; | |
| 721 | + U8 p; | |
| 722 | + AnubisProcess * processItem; | |
| 723 | + U32 nbProcess = TheAnubisProcessList->GetCount(); | |
| 724 | + for (i = nbProcess - 1; i != ~(U32)0; i--) // i-- with i unsigned and i = 0 is 111111111...1111 = ~0 | |
| 725 | + { | |
| 726 | + processItem = TheAnubisProcessList->GetProcessAt(i); | |
| 727 | + if (!processItem) continue; | |
| 728 | + TheAnubisProcessList->SetRunningProcess(processItem); | |
| 729 | + AnubisProcess::anbStatus st = processItem->GetStatus(); | |
| 730 | + p = processItem->GetPriority(); | |
| 731 | + switch (st) | |
| 732 | + { | |
| 733 | + case AnubisProcess::running: | |
| 734 | + case AnubisProcess::waiting_for_event: | |
| 735 | + case AnubisProcess::waiting_for_condition: // machine in a 'wait for' loop | |
| 736 | + case AnubisProcess::waiting_for_completion: // of a child process ('execute') | |
| 737 | + result = sup(p,result); | |
| 738 | + break; | |
| 739 | + | |
| 740 | + default: | |
| 741 | + break; | |
| 742 | + } | |
| 743 | + } | |
| 744 | + return result; | |
| 745 | +} | |
| 716 | 746 | |
| 717 | 747 | |
| 748 | +/* computing the credit for running a machine */ | |
| 749 | +static U32 compute_credit(U8 M, /* maximum of credit of all running machines */ | |
| 750 | + U8 L) /* priority of the machine */ | |
| 751 | +{ | |
| 752 | + /* the formula for M - 16 < L < M: | |
| 753 | + M - L | |
| 754 | + result = D(1 - -----) = ((D<<4) - D(M-L))>>4 | |
| 755 | + 16 | |
| 756 | + | |
| 757 | + where D = default maximal credit (max_steps) | |
| 758 | + M = max priority of running processes | |
| 759 | + L = priority of process | |
| 760 | + */ | |
| 761 | +#define D (max_steps) | |
| 762 | + int32 result; | |
| 763 | + do { | |
| 764 | + if (L >= M) result = max_steps; | |
| 765 | + else if (L <= (M - 16)) result = 0; | |
| 766 | + else result = ((D<<4) - D*(M-L))>>4; | |
| 767 | + } while(0); | |
| 768 | +#undef D | |
| 769 | + return (U32)result; | |
| 770 | +} | |
| 771 | + | |
| 718 | 772 | |
| 719 | 773 | /* The scheduler */ |
| 720 | 774 | void schedul(void) |
| ... | ... | @@ -723,6 +777,7 @@ void schedul(void) |
| 723 | 777 | U32 running_machines; |
| 724 | 778 | U32 waiting_machines; |
| 725 | 779 | U32 waiting_for_completion_machines; |
| 780 | + U32 max_running_priority; /* the maximum of the priority levels of all running (non sleeping) machines */ | |
| 726 | 781 | U32 steps = 0; |
| 727 | 782 | U32 activity = 0; |
| 728 | 783 | U32 wmm, wsm, maf; |
| ... | ... | @@ -770,6 +825,8 @@ void schedul(void) |
| 770 | 825 | steps = 0; |
| 771 | 826 | U32 nbProcess = TheAnubisProcessList->GetCount(); |
| 772 | 827 | AnubisProcess * processItem; |
| 828 | + | |
| 829 | + max_running_priority = max_priority_of_runnings(); | |
| 773 | 830 | |
| 774 | 831 | //for (i = nbProcess - 1; i >= 0; i--) |
| 775 | 832 | for (i = nbProcess - 1; i != ~(U32)0; i--) // i-- with i unsigned and i = 0 is 111111111...1111 = ~0 |
| ... | ... | @@ -794,13 +851,20 @@ void schedul(void) |
| 794 | 851 | case CM::AnubisProcess::machine_not_used: |
| 795 | 852 | break; |
| 796 | 853 | |
| 797 | - case AnubisProcess::running: | |
| 798 | - steps = processItem->RunMachine(max_steps) ; | |
| 854 | + case AnubisProcess::running: | |
| 855 | +#if 0 | |
| 856 | + { /* debugging tool */ | |
| 857 | + U8 p = processItem->GetPriority(); | |
| 858 | + U32 c = compute_credit(max_running_priority,p); | |
| 859 | + if (p != 255) { printf("<%d|%d>",p,c); fflush(stdout); } | |
| 860 | + } | |
| 861 | +#endif | |
| 862 | + steps = processItem->RunMachine(compute_credit(max_running_priority,processItem->GetPriority())) ; | |
| 799 | 863 | break; |
| 800 | 864 | |
| 801 | 865 | case AnubisProcess::waiting_for_event: |
| 802 | 866 | processItem->SetStatus(AnubisProcess::running); |
| 803 | - steps = processItem->RunMachine(max_steps); | |
| 867 | + steps = processItem->RunMachine(compute_credit(max_running_priority,processItem->GetPriority())); | |
| 804 | 868 | break; |
| 805 | 869 | |
| 806 | 870 | case AnubisProcess::waiting_for_condition: // machine in a 'wait for' loop |
| ... | ... | @@ -808,12 +872,12 @@ void schedul(void) |
| 808 | 872 | if (timevalless(processItem->GetAlarm(),¤t_time)) |
| 809 | 873 | { |
| 810 | 874 | processItem->SetStatus(AnubisProcess::running); |
| 811 | - steps = processItem->RunMachine(max_steps); | |
| 875 | + steps = processItem->RunMachine(compute_credit(max_running_priority,processItem->GetPriority())); | |
| 812 | 876 | } |
| 813 | 877 | break; |
| 814 | 878 | |
| 815 | 879 | case AnubisProcess::waiting_for_completion: // of a child process ('execute') |
| 816 | - steps = processItem->RunMachine(max_steps); | |
| 880 | + steps = processItem->RunMachine(compute_credit(max_running_priority,processItem->GetPriority())); | |
| 817 | 881 | break; |
| 818 | 882 | |
| 819 | 883 | case AnubisProcess::need_bigger_stack: |
| ... | ... | @@ -1011,7 +1075,7 @@ void schedul(void) |
| 1011 | 1075 | { |
| 1012 | 1076 | //LOGERROR("CRITICAL ERROR: Main VM select() failed with error [%d].\n", LAST_SOCKET_ERROR); |
| 1013 | 1077 | usleep(1000); // this will ensure that we won't take all the CPU time if a socket is |
| 1014 | - // invalid (bug encountered on 2007-08-15 by CR) | |
| 1078 | + // invalid (bug encountered on 2007-08-15 by CR) | |
| 1015 | 1079 | } |
| 1016 | 1080 | #else |
| 1017 | 1081 | // select(FD_SETSIZE,&rfds,NULL,NULL,alarm_set ? (&time_to_wait) : NULL); |
| ... | ... | @@ -1597,6 +1661,7 @@ int main(int argc, char **argv) |
| 1597 | 1661 | AnubisProcess * currentProcess; |
| 1598 | 1662 | /* create a new Anubis Process, the first one. */ |
| 1599 | 1663 | currentProcess = TheAnubisProcessList->CreateAnubisProcess((the_primary_module.byte_code)+8+(the_primary_module.starting_point), |
| 1664 | + 255, /* priority of 'mother' process */ | |
| 1600 | 1665 | TheAnubisAllocator); |
| 1601 | 1666 | |
| 1602 | 1667 | ... | ... |
anubis_dev/vm/src/vm.cpp
| ... | ... | @@ -5754,7 +5754,70 @@ ci_decl(start) |
| 5754 | 5754 | |
| 5755 | 5755 | AnubisProcess * newProcess; |
| 5756 | 5756 | newProcess = TheAnubisProcessList-> |
| 5757 | - CreateAnubisProcess(MAM(m_IP)+6, /* new machine starting point */ | |
| 5757 | + CreateAnubisProcess(MAM(m_IP)+6, /* new machine starting point (6 is the size of the 'start' instruction) */ | |
| 5758 | + MAM(m_priority), /* priority level of current process */ | |
| 5759 | + MAM(m_allocator)); | |
| 5760 | + | |
| 5761 | + //printf("[%d] Creating new process. Starting %d. PID = %d\n", MAM(m_pid), relative_IP(MAM(m_IP)+6), newProcess->GetPid()); | |
| 5762 | + if (!newProcess) | |
| 5763 | + /* cannot start a new machine yet, retry at next run */ | |
| 5764 | + { | |
| 5765 | + MAM(m_steps) = 0; | |
| 5766 | + return; | |
| 5767 | + } | |
| 5768 | + | |
| 5769 | + /* the new machine has been started */ | |
| 5770 | +#ifndef normal_machine | |
| 5771 | +#undef MAM(m_SP_begin) | |
| 5772 | +#endif | |
| 5773 | + new_stack = newProcess->GetSPBegin(); | |
| 5774 | +#ifndef normal_machine | |
| 5775 | +#define MAM(m_SP_begin) (MAM(m_SP_begin)) | |
| 5776 | +#endif | |
| 5777 | + new_stack[0] = 0; /* last return */ | |
| 5778 | + for (i = d; i >= 1; i--) | |
| 5779 | + new_stack[d-i+1] = *(MAM(m_SP)-i); | |
| 5780 | + | |
| 5781 | +#ifndef normal_machine | |
| 5782 | +#undef MAM(m_SP) | |
| 5783 | +#endif | |
| 5784 | + newProcess->SetSP(new_stack + d + 1); | |
| 5785 | +#ifndef normal_machine | |
| 5786 | +#define MAM(m_SP) (MAM(m_SP)) | |
| 5787 | +#endif | |
| 5788 | + | |
| 5789 | + MAM(m_IP) = (U8 *)get32(2); | |
| 5790 | +} | |
| 5791 | + | |
| 5792 | + | |
| 5793 | + | |
| 5794 | + | |
| 5795 | +/* Format: startp (U8)depth (U32)addr | |
| 5796 | +Size: 6 | |
| 5797 | + | |
| 5798 | +This instruction starts a new virtual machine. The 'depth' argument is the number of | |
| 5799 | +items which should be copied from the top of the stack of the current machine, to the | |
| 5800 | +stack of the new machine. These items are just words. There is no virtual copy to | |
| 5801 | +perform. They have been already done by the instructions just before 'start'. | |
| 5802 | + | |
| 5803 | +The priority level (a Word8) is in R. | |
| 5804 | + | |
| 5805 | +'addr' is the address to which the current machine should jump after starting the new | |
| 5806 | +machine. The new machine itself executes the code following this 'start' | |
| 5807 | +instruction. | |
| 5808 | + | |
| 5809 | + */ | |
| 5810 | +ci_decl(startp) | |
| 5811 | +{ | |
| 5812 | + trace | |
| 5813 | + U32 *new_stack = NULL; | |
| 5814 | + U8 d = get8(1); | |
| 5815 | + U8 i; | |
| 5816 | + | |
| 5817 | + AnubisProcess * newProcess; | |
| 5818 | + newProcess = TheAnubisProcessList-> | |
| 5819 | + CreateAnubisProcess(MAM(m_IP)+6, /* new machine starting point (6 is the size of the 'start' instruction) */ | |
| 5820 | + MAM(m_R), /* priority level of new process */ | |
| 5758 | 5821 | MAM(m_allocator)); |
| 5759 | 5822 | |
| 5760 | 5823 | //printf("[%d] Creating new process. Starting %d. PID = %d\n", MAM(m_pid), relative_IP(MAM(m_IP)+6), newProcess->GetPid()); | ... | ... |
anubis_dev/vm/src/vm.h
| ... | ... | @@ -216,7 +216,7 @@ extern void serialize_float(double d, U8 *dest); |
| 216 | 216 | struct Exec_Mod_struct { |
| 217 | 217 | U32 flags; /* also indicates is primary or secondary ('mf_secondary_adm' in 'bytecode.h') */ |
| 218 | 218 | //U32 code_size; |
| 219 | - /* since version 1.13, the 'byte_code' field does not only contain only the code. | |
| 219 | + /* since version 1.13, the 'byte_code' field does not contain only the code. | |
| 220 | 220 | It is an actual byte array, i.e. has the following form: |
| 221 | 221 | |
| 222 | 222 | +---------+---------+------------------------------------------- |
| ... | ... | @@ -224,7 +224,7 @@ struct Exec_Mod_struct { |
| 224 | 224 | +---------+---------+------------------------------------------- |
| 225 | 225 | 0 4 8 |
| 226 | 226 | |
| 227 | - This byte array contains its own size. This why the field 'code_size' has been removed. | |
| 227 | + This byte array contains its own size. This is why the field 'code_size' has been removed. | |
| 228 | 228 | |
| 229 | 229 | An array of Exec_Mod_struct (see dynamic_module.cpp) contains all currently loaded modules. |
| 230 | 230 | Only the primary module is permanent, hence has its counter 'cnt' always at 0. | ... | ... |
anubis_dev/vm/src/vmtools.cpp