Commit 81bd6d5a4e5d41556d40914cdd1bb74e01b6157d

Authored by Alain Prouté
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)
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
... ... @@ -168,6 +168,7 @@ typedef enum
168 168 item(read_locvar)\
169 169 item(write_locvar)\
170 170 item(start)\
  171 + item(startp)\
171 172 item(finish)\
172 173 item(copy_stack_ptr)\
173 174 item(copy_stack_mixed)\
... ...
anubis_dev/include/minver.h
1 1 #define maj_version (1)
2   -#define min_version (13)
3   -#define rel_version (5)
  2 +#define min_version (14)
  3 +#define rel_version (0)
4 4 #define build_version (0)
5 5  
6 6  
... ...
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 &amp;&amp; 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&#39;&#39; 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&#39;&#39; (``process&#39;&#39; 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(),&current_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
... ... @@ -1013,6 +1013,7 @@ void link_globals_and_relocate(U8* code,
1013 1013 case i_mvar_slots_del_mixed:
1014 1014 case i_indirect_del_mixed:
1015 1015 case i_start:
  1016 + case i_startp:
1016 1017 case i_type_mixed:
1017 1018 case i_indirect_type_mixed:
1018 1019 if (nsc_file != NULL)
... ...
anubis_distrib/linux_install/prepare_package/Makefile
1 1  
2   -minnum = 13
3   -relnum = 5
  2 +minnum = 14
  3 +relnum = 0
4 4 bldnum = 0
5 5  
6 6 package:
... ...