home *** CD-ROM | disk | FTP | other *** search
- /* GRAPHIC LISP */
- /* Scritto nel 1991-94 da Zoia Andrea Michele */
- /* Via Pergola #1 Tirano (SO) Tel. 0342-704210 */
- /* file closnode.c */
-
- /* #define CLOSNODE_DEBUG */
-
- #include "clos.h"
-
- /* definizioni interne */
- #define BYTES_IN_PAGE 60000L /* al max 30 Mega di memoria */
- #define MAX_PAGES 500 /* se ne serve di più(!!) basta aumentare questo valore */
- #define NULLHND Q(NULL) /* P(NULLHND)==NULL */
-
- /* variabili interne */
- node lastalloc_node; /* punta all' ultimo nodo allocato */
- node lastlock_node; /* punta all'ultimo nodo LOCK */
-
- BOOL GCInProgress;
- node_s **pages_array; /* array di pagine di memoria */
- unsigned int total_pages=0; /* pagine totali */
- lsiz_t TotalNodes; /* nodi totali */
-
- /* funzioni interne */
- void node_marklist();
-
-
- int node_malloc(num)
- lsiz_t num;
- {
- unsigned int nodes_p,bytes_p,num_p,nodes_r,bytes_r,i,j;
- node_s *np, *prec;
- int first_flag=TRUE;
- node free_list;
-
- pages_array=NULL;
- if(num<(lsiz_t)2)
- return error(E_CHEKZ,ERR_MINTERNAL|ERR_TNORM|ERR_PVOID,NULL);
-
- pages_array=malloc(MAX_PAGES*sizeof(node_s*));
- if(pages_array==NULL)return ERROR;
-
- TotalNodes=num;
- nodes_p=(unsigned)(BYTES_IN_PAGE/sizeof(node_s));
- bytes_p=nodes_p*sizeof(node_s);
-
- num_p=total_pages=(unsigned int)(num/(unsigned long int)nodes_p);
- nodes_r=(unsigned int)(num%(unsigned long int)nodes_p);
- bytes_r=nodes_r*sizeof(node_s);
-
- if(bytes_r){
- num_p++;
- total_pages++;
- }
- if(num_p>MAX_PAGES)
- return error(E_PAGES,ERR_MINTERNAL|ERR_TNORM|ERR_PVOID,NULL);
-
- #define BYTES_P ( (!i && bytes_r) ? bytes_r: bytes_p )
- #define NODES_P ( (!i && nodes_r) ? nodes_r: nodes_p )
-
- for(i=0;i<num_p;i++){
- if((np=pages_array[i]=(node_s *)malloc(BYTES_P))==NULL){
- for(j=0;j<i;j++)
- free((void *)pages_array[j]);
- pages_array[0]=NULL;
- /* segnala che non si e' allocata la memoria */
- return ERROR;
- }
- for(j=0;j<NODES_P;j++){
- np->type=NT_NEW_NODE_T;
- if(first_flag){
- prec=np++;
- free_list=(node)prec;
- /* (node_s*)free_list=prec; */
- /* P(free_list)=prec; errore di BCC2.0 BUG DEL COMPILATORE !!*/
- /* P(free_list)=prec=np++; BCC2.0 da errore !?!?!?*/
- first_flag=FALSE;
- }else{
- prec->next=Q(np++);
- prec=P(prec->next);
- }
- }
- }
- prec->next=NULLHND;
-
- #undef BYTES_P
- #undef NODES_P
- /*
- la free-list si chiude con NULLHND
- e subito si alloca un nodo speciale(VOID)
- in cima ala lista dei nodi
- */
-
- lastalloc_node=VOID=free_list; /* si assegna lastalloc_node=VOID */
-
- lastlock_node=VOID; /* si assegna lock-list */
- LOCK(VOID); /* e lo si marca come bloccato */
-
- return OK;
- }
-
- void node_free()
- {
- unsigned i;
- if(pages_array){
- /* se non si e' gia' disallocato */
- for(i=0;i<total_pages;i++)
- free((void *)pages_array[i]);
- free(pages_array);
- }
- pages_array=NULL;
- }
-
-
- #ifdef __NOINLINE__
- /****************** funzioni definite INLINE in clos.h ****************/
- node node_make()
- {
- /* alloca un nodo recuperandolo dopo lastalloc_node*/
-
- if(!P(NEXT(lastalloc_node))){
- node_gc();
- if(!P(NEXT(lastalloc_node))){
- error(E_NOMEMNODES,ERR_MERROR|ERR_PVOID|ERR_TCRIT,NULL);
- }
- }
-
- /*si blocca lastalloc_node e lo si mette nella lock-list*/
- lastalloc_node=NEXT(lastalloc_node);
- LOCK(lastalloc_node);
- NEXTLOCK(lastlock_node)=lastalloc_node;
- lastlock_node=lastalloc_node;
-
- return lastalloc_node;
- }
-
- /********************** INLINE ********************/
- node node_getlastlock()
- /* da chiamare prima di una funzione utente*/
- {
- return lastlock_node;
- }
-
- /*********************** INLINE ********************/
- node node_lock(n)
- node n;
- {
- /* blocca il nodo n e tutta la sua sottolista */
- FIX(n);
- if(IS_LOCK(n))return n;
- LOCK(n);
- NEXTLOCK(lastlock_node)=n;
- return lastlock_node=n;
- }
- /*********************************************/
- #endif
-
- node node_alloc(s)
- char *s;
- {
- /* ritorna un nodo di nome *s se esiste altrimenti lo alloca */
- /* da non chiamare con s=NULL */
- node tmp;
- hash_t h;
- if( (tmp=hash_search(s,&h))==VOID ){
- /* il nodo non e' mai stato allocato */
- /* e node_make lo mette nella lock-list */
- tmp=node_make();
- NAME(tmp)=string_put(s,tmp);
- HASH(tmp)=h;
- TYPE(tmp)|=NT_HAS_NAME+NT_IS_NAME;
- hash_put(tmp,h);
- return tmp;
- }
- /* il nodo era gia' stato allocato */
- /* se non e' nella lock-list ce lo si mette */
- if(!IS_LOCK(tmp)){
- LOCK(tmp);
- NEXTLOCK(lastlock_node)=tmp;
- lastlock_node=tmp;
- }
- return tmp;
- }
-
-
- node node_lockreset()
- /* distrugge la lock-list */
- /* e' usata solo per entrare nel main-loop */
- {
- node punt;
-
- NEXTLOCK(lastlock_node)=NULLHND;
- punt=NEXTLOCK(VOID);
- while(P(punt)){
- /* if(!IS_LOCK(punt))printf ("ERR\n"); */
- UNLOCK(punt);
- UNFIX(punt);
- punt=NEXTLOCK(punt);
- }
- return lastlock_node=VOID;
- }
- void node_signal(lastlock)
- node lastlock;
- {
- /* da chiamare alla fine di una funzione utente */
- /* accorcia la lock-list */
- NEXTLOCK(lastlock_node)=NULLHND;
- lastlock_node=lastlock;
- while(P(lastlock=NEXTLOCK(lastlock)))
- TYPE(lastlock)&=(~(NT_IS_LOCK+NT_IS_FIX));
- }
-
- void node_gc()
- {
- static node punt;
- static node prec_used;
- static node prec_free;
- static node free_list;
- static n_type punt_type;
- static node_s pfns;
-
- GCInProgress=TRUE;
-
- /* mark-phase */
- if(config.gcbeep)cl_beep(500);
-
- /* 1) marca tutti i nodi globali */
- free_list=NEXT(lastalloc_node);
- NEXT(lastalloc_node)=NULLHND;
- /* l'istruzione sopra stacca tutti i nodi ancora liberi */
- /* per cui l'inizio della lista va salvato in free_list */
- /* free_list non e' vuota solo se si invoca il gc direttamente da */
- /* programma o da linea di comando */
- punt=VOID;
- while(P(punt=NEXT(punt)))
- if(IS_NAME(punt))
- if(HAS_NAME(punt))
- if(HAS_SOMETHING(punt))
- node_marklist(punt);
-
- /* 2) marca tutti i nodi FIX nella lock-list */
- /* OPT 2: Quando si scorre tutta la lista dei nodi nel pezzo sopra */
- /* basta controllare che si trovi un nodo FIX e recuperarlo */
- /* senza scandire tutta la lock-list */
- /* Pero' aggiungere un test sopra e' generalmente piu' pesante che scandire tutta*/
- /* la lock-list. */
-
- NEXTLOCK(lastlock_node)=NULLHND;
- punt=VOID;
- while(P(punt=NEXTLOCK(punt)))
- if(IS_FIX(punt))
- node_marklist(punt);
-
- /* 3) marca tutti i nodi nella lock-list */
- /* OPT 1:SI PUO' FAR RECUPERARE AL GC TUTTI I NODI LOCK OLTRE A QUELLI MARK */
-
-
- /* sweep phase */
- /* recupera tutti i nodi MARK */
- /* e azzera il flag MARK */
- if(config.gcbeep)cl_beep(250);
-
- punt=NEXT(VOID); /* salta VOID */
- prec_used=VOID;
- prec_free=Q(&pfns);
- while(P(punt)){
- /* scandisce tutta la lista dei nodi allocati */
- /* (e anche liberi se gc la si chiama dalla riga di comando) */
- punt_type=TYPE(punt);
- if(punt_type& (NT_IS_MARK+NT_IS_LOCK)){
- /* salva solo i nodi che sono MARK e/o LOCK VEDI OPT 1*/
- UNMARK(punt);
- NEXT(prec_used)=punt;
- prec_used=punt;
- punt=NEXT(punt);
- continue;
- }
- switch(punt_type&NT_IS_MASK){
- case NT_IS_NAME:
- if(punt_type&NT_HAS_NAME){
- hash_del(HASH(punt));
- string_del(NAME(punt));
- }
- break;
- case NT_IS_VALUE:
- if((punt_type&NT_MASK)==NT_STRING)
- string_del(STRING(punt));
- break;
- }
- TYPE(punt)=NT_NEW_NODE_T;
- NEXT(prec_free)=punt;
- prec_free=punt;
- punt=NEXT(punt);
- }
- /* prec_used punta all' ultimo nodo allocato */
- /* prec_free punta all' ultimo nodo liberato dal GC */
- /* free_list punta al primo nodo libero non passato dal GC */
- /* VOID punta al primo nodo allocato */
- /* pfns contiene il puntatore al primo nodo liberato dal GC */
-
- /* se non si trovano nodi liberi prec_free=pfns */
- /* e se free_list e' vuota allora pfns->NULL */
- NEXT(prec_free)=free_list;
- /* prec used e' al limite uguale a VOID */
- NEXT(lastalloc_node=prec_used)=NEXT(Q(&pfns));
-
-
- if(config.gcbeep)cl_beep(0);
- GCInProgress=FALSE;
- #ifdef _Windows
- SendMessage(hResourceWindow,WM_TIMER,1,0);
- #endif
- }
-
-
- void node_marklist(list)
- node list;
- {
- if(IS_MARK(list)){return;}
- MARK(list);
- switch(GET_NTYPE(list)){
- case NT_IS_CONS:
- node_marklist(CONSLEFT(list));
- node_marklist(CONSRIGHT(list));
- return;
- case NT_IS_VALUE:
- switch(GET_VTYPE(list)){
- case NT_CNAME:
- node_marklist(CNAME(list));
- return;
- case NT_ENAME:
- node_marklist(ENAME(list));
- return;
- case NT_METHOD:
- node_marklist(METHOD(list));
- return;
- case NT_CLASS:
- node_marklist(CLASS_INSTANCE(list));
- return;
- case NT_UFUNC:
- case NT_MACRO:
- node_marklist(UFUNC_TYPE(list));
- node_marklist(UFUNC_PAR(list));
- node_marklist(UFUNC_ENV(list));
- node_marklist(UFUNC_SEX(list));
- node_marklist(UFUNC_KEY(list));
- node_marklist(UFUNC_AUX(list));
- node_marklist(UFUNC_OPT(list));
- node_marklist(UFUNC_REST(list));
- return;
- }
- return;
- case NT_IS_NAME:
- if(HAS_VALUE(list)||HAS_BIND(list)) node_marklist(VALUE(list));
- if(HAS_FUNCTION(list)) node_marklist(FUNCTION(list));
- if(HAS_PLIST(list)) node_marklist(PLIST(list));
- if(HAS_CLASS(list)) node_marklist(CLASS(list));
- return;
- }
- error(E_NULLGC,ERR_MINTERNAL|ERR_TNORM|ERR_PVOID,NULL);
- }
-
-
-
-
-
- node node_scan()
- {
- /* genera una lista di tutti i nomi che contengono qualcosa */
- /* e' usata da objlist */
-
- node punt=NEXT(VOID); /* salta VOID */
- node n=NIL;
- node c;
- while(P(punt)){
- if(IS_NAME(punt) && HAS_NAME(punt) && HAS_SOMETHING(punt)){
- c=node_make();
- TYPE(c)|=NT_IS_CONS;
- CONSLEFT(c)=punt;
- CONSRIGHT(c)=n;
- n=c;
- }
- punt=NEXT(punt);
- }
- return n;
- }
-
- node node_scan_fix()
- {
- /* genera una lista di tutti i nodi FIX */
- /* e' usata da fixlist */
-
- node punt=NEXT(VOID); /* salta VOID */
- node n=NIL;
- node c;
- while(P(punt)){
- if(IS_FIX(punt)){
- c=node_make();
- TYPE(c)|=NT_IS_CONS;
- CONSLEFT(c)=punt;
- CONSRIGHT(c)=n;
- n=c;
- }
- punt=NEXT(punt);
- }
- return n;
- }
-
-
-
-
-
-
-
-
-
-
- void node_count(used,free)
- lsiz_t *used;
- lsiz_t *free;
- {
- node n;
-
- *used=1;
- n=VOID;
- while(n!=lastalloc_node){
- (*used)++;
- n=NEXT(n);
- }
- *free=0;
- n=NEXT(lastalloc_node);
- while(P(n)){
- (*free)++;
- n=NEXT(n);
- }
- if((*used)+(*free) != TotalNodes)
- error(E_BADNCCOUNT,ERR_MINTERNAL|ERR_TNORM|ERR_PVOID,NULL);
- }
-
-
- void node_criticalgc()
- {
- if(GCInProgress){
- GCInProgress=FALSE;
- lisp_print_string("Stack overflow durante un GC\nUscire dall'interprete\n",stdout);
- }
- }
-