PageRenderTime 63ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/libsrc/interpreter/list.c

https://gitlab.com/oytunistrator/QuIP
C | 617 lines | 416 code | 101 blank | 100 comment | 137 complexity | f9d00001b1c34e88ce219e0d825c8ecd MD5 | raw file
  1. #include "quip_config.h"
  2. #include "quip_prot.h"
  3. /* the term "ring" refers to a circular list
  4. rings have head and tail pointers, which should
  5. point to adjacent elements, but the tail pts
  6. forward to the head and the head pts backward to
  7. the tail
  8. */
  9. static List *free_node_list=NO_LIST;
  10. static List *free_list_list=NO_LIST;
  11. //static u_long node_debug=NODE_DEBUG_MASK;
  12. #ifdef QUIP_DEBUG
  13. //static u_long node_debug=0;
  14. #endif // QUIP_DEBUG
  15. static u_long total_nodes=0;
  16. static Node * safe_remHead(List *lp);
  17. static void safe_addTail(List *lp,Node *np);
  18. int n_active_threads=0;
  19. void report_node_data(SINGLE_QSP_ARG_DECL)
  20. {
  21. sprintf(ERROR_STRING,"%ld nodes allocated",total_nodes);
  22. ADVISE(ERROR_STRING);
  23. if( free_node_list == NO_LIST )
  24. ADVISE("no nodes freed");
  25. else {
  26. sprintf(ERROR_STRING,
  27. "%d free nodes available",eltcount(free_node_list));
  28. ADVISE(ERROR_STRING);
  29. }
  30. if( free_list_list == NO_LIST )
  31. ADVISE("no lists freed");
  32. else {
  33. sprintf(ERROR_STRING,
  34. "%d free lists available",eltcount(free_list_list));
  35. ADVISE(ERROR_STRING);
  36. }
  37. }
  38. /*
  39. * remove a node from a list
  40. * returns removed node or NO_NODE if not in list
  41. */
  42. Node *remNode( List * lp, Node* node )
  43. /* lp = nlist to be searched */
  44. /* node = node to be searched for */
  45. {
  46. Node *np;
  47. int is_ring=0;
  48. np=QLIST_HEAD(lp);
  49. if( np == NO_NODE ) return(NO_NODE);
  50. LOCK_LIST(lp)
  51. if( NODE_PREV(np) != NO_NODE ) is_ring=1;
  52. while( np != NO_NODE ){
  53. if( np==node ){
  54. if( NODE_PREV(np) != NO_NODE )
  55. SET_NODE_NEXT(NODE_PREV(np),NODE_NEXT(np));
  56. else SET_QLIST_HEAD(lp, NODE_NEXT(np));
  57. if( NODE_NEXT(np) != NO_NODE )
  58. SET_NODE_PREV(NODE_NEXT(np),NODE_PREV(np));
  59. else SET_QLIST_TAIL(lp, NODE_PREV(np));
  60. /* the above doesn't work for rings!! */
  61. if( is_ring ){
  62. if( QLIST_HEAD(lp) == np ){
  63. if( QLIST_TAIL(lp) == np ){
  64. SET_QLIST_HEAD(lp,NO_NODE);
  65. SET_QLIST_TAIL(lp,NO_NODE);
  66. } else SET_QLIST_HEAD(lp,NODE_NEXT(np));
  67. } else if( QLIST_TAIL(lp) == np ){
  68. SET_QLIST_TAIL(lp, NODE_PREV(np));
  69. }
  70. SET_NODE_NEXT(np,np);
  71. SET_NODE_PREV(np,np);
  72. } else {
  73. SET_NODE_NEXT(np,NO_NODE);
  74. SET_NODE_PREV(np,NO_NODE);
  75. }
  76. return(np);
  77. }
  78. np = NODE_NEXT(np);
  79. if( np == QLIST_HEAD(lp) ) np=NO_NODE;
  80. }
  81. UNLOCK_LIST(lp)
  82. return(np);
  83. }
  84. /*
  85. * search list for node pointing to data
  86. * returns pointer to node or NO_NODE
  87. */
  88. Node *nodeOf( List *lp, void* data )
  89. /* list to be searched */
  90. /* data target node should point to */
  91. {
  92. Node *np;
  93. np=QLIST_HEAD(lp);
  94. while( np != NO_NODE ){
  95. if( np->n_data == data ) return(np);
  96. np=NODE_NEXT(np);
  97. if( np==QLIST_HEAD(lp) ) np=NO_NODE;
  98. }
  99. return(NO_NODE);
  100. }
  101. Node *remData( List *lp, void* data ) /** remove node pointing to data */
  102. {
  103. Node *np, *stat;
  104. np=nodeOf( lp, data );
  105. if( np==NO_NODE )
  106. return(NO_NODE);
  107. stat=remNode( lp, np );
  108. //#ifdef CAUTIOUS
  109. // if( stat == NO_NODE ){
  110. // NWARN("CAUTIOUS: remData: remNode failed");
  111. // return(NO_NODE);
  112. // }
  113. //#endif /* CAUTIOUS */
  114. assert( stat != NO_NODE );
  115. return(np);
  116. }
  117. Node *nth_elt( List *lp , count_t n ) /** get ptr to nth node from head */
  118. {
  119. Node *np, *np0;
  120. // count_t is unsigned?
  121. //if( n < 0 ) return(NO_NODE);
  122. np0=np=QLIST_HEAD(lp);
  123. while( n-- ) {
  124. if( np==NO_NODE )
  125. return( NO_NODE );
  126. np=NODE_NEXT(np);
  127. if( np==np0 )
  128. return( NO_NODE );
  129. }
  130. return( np );
  131. }
  132. Node *nth_elt_from_tail( List *lp , count_t n )
  133. {
  134. Node *np, *np0;
  135. np0=np=QLIST_TAIL(lp);
  136. while( n-- ) {
  137. if( np==NO_NODE )
  138. return( NO_NODE );
  139. np=NODE_PREV(np);
  140. if( np==np0 )
  141. return( NO_NODE );
  142. }
  143. return( np );
  144. }
  145. count_t eltcount( List * lp ) /** returns number of elements (for rings too) */
  146. {
  147. int i=0;
  148. Node *np;
  149. Node *np0;
  150. if( lp==NO_LIST ) return(0);
  151. np0=np=QLIST_HEAD(lp);
  152. while( np!=NO_NODE ){
  153. i++;
  154. np=NODE_NEXT(np);
  155. if( np==np0 ) np=NO_NODE;
  156. }
  157. return(i);
  158. }
  159. /*
  160. * Put node np on the list of free and available nodes
  161. * we used to test free_node_list here, but since it gets initialized
  162. * in newnodw(), we now no longer need to...
  163. */
  164. void rls_node(Node *np)
  165. {
  166. #ifdef QUIP_DEBUG
  167. //if( debug & node_debug ){
  168. //sprintf(DEFAULT_ERROR_STRING,"releasing node 0x%lx",(u_long)np);
  169. //NADVISE(DEFAULT_ERROR_STRING);
  170. //}
  171. #endif /* QUIP_DEBUG */
  172. addHead(free_node_list,np);
  173. }
  174. /*
  175. * Return a pointer to a node.
  176. * If there is one available on the free list, return it, otherwise
  177. * allocate memory for a new one.
  178. */
  179. static Node *newnode() /**/
  180. {
  181. Node *np;
  182. // what if free_node_list doesn't exist???
  183. // BUG? we might want to lock free_node_list,
  184. // but in practice this will be executed early,
  185. // before a second thread has been created...
  186. if( free_node_list == NO_LIST )
  187. free_node_list = new_list();
  188. LOCK_LIST(free_node_list)
  189. if( IS_EMPTY(free_node_list) ){ /* grab another page's worth of nodes */
  190. int n_per_page;
  191. n_per_page = 4096 / sizeof(Node); /* BUG use symbolic const */
  192. #ifdef QUIP_DEBUG
  193. //if( debug & node_debug ){
  194. //sprintf(DEFAULT_ERROR_STRING,"allocating memory for %d more nodes (old total=%ld)",
  195. //n_per_page,total_nodes);
  196. //NADVISE(DEFAULT_ERROR_STRING);
  197. //}
  198. #endif /* QUIP_DEBUG */
  199. np = (Node *) malloc( n_per_page * sizeof(Node) );
  200. if( np == NO_NODE ){
  201. sprintf(DEFAULT_ERROR_STRING,
  202. "no more memory for nodes (%ld allocated)",
  203. total_nodes);
  204. NERROR1(DEFAULT_ERROR_STRING);
  205. }
  206. total_nodes += n_per_page;
  207. while( n_per_page-- ) {
  208. /* Originally, we didn't initialize these nodes...
  209. * That worked OK until we ran on the SUN
  210. * under a peculiar set of circumstances...
  211. */
  212. init_node(np,NULL);
  213. safe_addTail(free_node_list,np++);
  214. }
  215. }
  216. np=safe_remHead(free_node_list);
  217. UNLOCK_LIST(free_node_list)
  218. SET_NODE_NEXT(np,NO_NODE);
  219. SET_NODE_PREV(np,NO_NODE);
  220. np->n_pri = 0;
  221. np->n_data = NULL;
  222. #ifdef QUIP_DEBUG
  223. //if( debug & node_debug ){
  224. //sprintf(DEFAULT_ERROR_STRING,"newnode: np = 0x%lx",(u_long)np);
  225. //NADVISE(DEFAULT_ERROR_STRING);
  226. //}
  227. #endif /* QUIP_DEBUG */
  228. return(np);
  229. }
  230. /*
  231. * Release all of the nodes belonging to a list,
  232. * and then release the list pointer.
  233. */
  234. void dellist( List *lp )
  235. {
  236. rls_nodes_from_list(lp);
  237. rls_list(lp);
  238. }
  239. void rls_nodes_from_list(List *lp)
  240. {
  241. Node *np, *np2;
  242. LOCK_LIST(lp)
  243. np=QLIST_HEAD(lp);
  244. while( np != NO_NODE ){
  245. np2=np;
  246. np=NODE_NEXT(np2);
  247. rls_node(np2);
  248. if( np == QLIST_HEAD(lp) ) np=NO_NODE;
  249. }
  250. SET_QLIST_HEAD(lp,NO_NODE);
  251. SET_QLIST_TAIL(lp,NO_NODE);
  252. UNLOCK_LIST(lp)
  253. }
  254. static void init_list(List *lp)
  255. {
  256. //#ifdef CAUTIOUS
  257. // if( lp == NO_LIST ){
  258. // NERROR1("CAUTIOUS: init_list: null list pointer!?");
  259. // IOS_RETURN
  260. // }
  261. //#endif // CAUTIOUS
  262. assert( lp != NO_LIST );
  263. #ifdef THREAD_SAFE_QUERY
  264. #ifdef HAVE_PTHREADS
  265. int status;
  266. status = pthread_mutex_init(&lp->l_mutex,NULL);
  267. if( status != 0 ){
  268. NERROR1("error initializing mutex");
  269. IOS_RETURN
  270. }
  271. #endif /* HAVE_PTHREADS */
  272. //lp->l_flags=0;
  273. #endif /* THREAD_SAFE_QUERY */
  274. SET_QLIST_HEAD(lp,NO_NODE);
  275. SET_QLIST_TAIL(lp,NO_NODE);
  276. }
  277. /*
  278. * Return a pointer to a new list structure
  279. */
  280. List *new_list()
  281. {
  282. List *lp;
  283. if( free_list_list == NO_LIST || IS_EMPTY(free_list_list) ){
  284. lp=(List*) getbuf(sizeof(*lp));
  285. //if( lp == NO_LIST ) mem_err("new_list");
  286. if( lp == NO_LIST ) NERROR1("new_list");
  287. } else {
  288. Node *np;
  289. np=remHead(free_list_list);
  290. lp=(List *)np->n_data;
  291. rls_node(np);
  292. }
  293. init_list(lp);
  294. return(lp);
  295. }
  296. /*
  297. * Return a list pointer to the list of free list pointers
  298. */
  299. void rls_list(List *lp)
  300. {
  301. Node *np;
  302. if( free_list_list == NO_LIST )
  303. free_list_list = new_list();
  304. np=mk_node(lp);
  305. addHead(free_list_list,np);
  306. }
  307. void addHead( List *lp, Node* node ) /**/
  308. {
  309. LOCK_LIST(lp)
  310. if( QLIST_HEAD(lp) != NO_NODE ){
  311. if( NODE_PREV(QLIST_HEAD(lp)) != NO_NODE ){ /* ring */
  312. SET_NODE_PREV(node, QLIST_TAIL(lp));
  313. SET_NODE_NEXT(QLIST_TAIL(lp), node);
  314. }
  315. SET_NODE_PREV(QLIST_HEAD(lp), node);
  316. SET_NODE_NEXT(node, QLIST_HEAD(lp));
  317. } else {
  318. /* don't initialize this (for rings)
  319. SET_NODE_NEXT(node, NO_NODE);
  320. */
  321. SET_QLIST_TAIL(lp, node);
  322. }
  323. SET_QLIST_HEAD(lp, node);
  324. UNLOCK_LIST(lp)
  325. }
  326. #define ADD_TAIL(lp,np) \
  327. \
  328. if( QLIST_TAIL(lp) != NO_NODE ){ \
  329. if( NODE_NEXT(QLIST_TAIL(lp)) != NO_NODE ){ \
  330. SET_NODE_PREV(QLIST_HEAD(lp), np); \
  331. SET_NODE_NEXT(np, QLIST_HEAD(lp)); \
  332. } \
  333. SET_NODE_NEXT(QLIST_TAIL(lp), np); \
  334. SET_NODE_PREV(np, QLIST_TAIL(lp)); \
  335. } else { \
  336. SET_QLIST_HEAD(lp, np); \
  337. } \
  338. SET_QLIST_TAIL(lp, np);
  339. void addTail( List *lp, Node* np ) /**/
  340. {
  341. LOCK_LIST(lp)
  342. ADD_TAIL(lp,np)
  343. UNLOCK_LIST(lp)
  344. }
  345. void safe_addTail( List *lp, Node* np ) /**/
  346. {
  347. ADD_TAIL(lp,np)
  348. }
  349. #define REM_HEAD(np,lp) \
  350. \
  351. SET_QLIST_HEAD(lp, NODE_NEXT(np)); \
  352. if( NODE_PREV(np) != NO_NODE ){ /* ring */ \
  353. if( QLIST_HEAD(lp) == np ){ /* last node of ring list ? */ \
  354. SET_QLIST_TAIL(lp,NO_NODE); \
  355. SET_QLIST_HEAD(lp, NO_NODE); \
  356. } else { \
  357. SET_NODE_NEXT(NODE_PREV(np), NODE_NEXT(np)); \
  358. SET_NODE_PREV(NODE_NEXT(np), NODE_PREV(np)); \
  359. } \
  360. \
  361. /* keep it a ring link */ \
  362. SET_NODE_NEXT(np,np); \
  363. SET_NODE_PREV(np,np); \
  364. } else { \
  365. if( NODE_NEXT(np) != NO_NODE ) \
  366. SET_NODE_PREV(NODE_NEXT(np), NO_NODE); \
  367. else SET_QLIST_TAIL(lp, NO_NODE); \
  368. \
  369. SET_NODE_NEXT(np, NO_NODE); \
  370. SET_NODE_PREV(np, NO_NODE); \
  371. }
  372. Node *remHead( List *lp ) /**/
  373. {
  374. Node *np;
  375. if( (np=QLIST_HEAD(lp)) == NO_NODE ){
  376. return( NO_NODE );
  377. }
  378. LOCK_LIST(lp)
  379. REM_HEAD(np,lp)
  380. UNLOCK_LIST(lp)
  381. return(np);
  382. }
  383. Node *safe_remHead( List *lp ) /**/
  384. {
  385. Node *np;
  386. if( (np=QLIST_HEAD(lp)) == NO_NODE ){
  387. return( NO_NODE );
  388. }
  389. REM_HEAD(np,lp)
  390. return(np);
  391. }
  392. Node *remTail( List *lp ) /**/
  393. {
  394. Node *np;
  395. if( (np=QLIST_TAIL(lp)) == NO_NODE ) return(NO_NODE);
  396. LOCK_LIST(lp)
  397. SET_QLIST_TAIL(lp, NODE_PREV(np));
  398. if( NODE_NEXT(np) != NO_NODE ){ /* ring */
  399. if( QLIST_TAIL(lp) == np ){ /* last link of ring */
  400. SET_QLIST_TAIL(lp,NO_NODE);
  401. SET_QLIST_HEAD(lp,NO_NODE);
  402. } else {
  403. SET_NODE_PREV(NODE_NEXT(np), NODE_PREV(np));
  404. SET_NODE_NEXT(NODE_PREV(np), NODE_NEXT(np));
  405. }
  406. /* keep it a ring link */
  407. SET_NODE_NEXT(np,np);
  408. SET_NODE_PREV(np,np);
  409. } else {
  410. if( NODE_PREV(np) != NO_NODE ) /* last node */
  411. SET_NODE_NEXT(NODE_PREV(np), NO_NODE);
  412. else SET_QLIST_HEAD(lp,NO_NODE);
  413. SET_NODE_NEXT(np, NO_NODE);
  414. SET_NODE_PREV(np, NO_NODE);
  415. }
  416. UNLOCK_LIST(lp)
  417. return(np);
  418. }
  419. static void l_exch( List *lp, Node* np1, Node* np2 ) /** exchange two list elements */
  420. {
  421. Node tmp;
  422. Node *tmp_np=(&tmp);
  423. LOCK_LIST(lp)
  424. /* this procedure has to be different for adjacent nodes! */
  425. if( np1 == NODE_NEXT(np2) ){ /* np1 follows np2 */
  426. if( np2 != NODE_NEXT(np1) ){
  427. if( NODE_NEXT(np1) != NO_NODE )
  428. SET_NODE_PREV(NODE_NEXT(np1),np2);
  429. if( NODE_PREV(np2) != NO_NODE )
  430. SET_NODE_NEXT(NODE_PREV(np2),np1);
  431. SET_NODE_NEXT(np2,NODE_NEXT(np1));
  432. SET_NODE_PREV(np1,NODE_PREV(np2));
  433. SET_NODE_NEXT(np1,np2);
  434. SET_NODE_PREV(np2,np1);
  435. }
  436. /* else two element ring; do nothing 'cept fix head & tail */
  437. } else if( np2 == NODE_NEXT(np1) ){
  438. if( NODE_PREV(np1) != NO_NODE )
  439. SET_NODE_NEXT(NODE_PREV(np1),np2);
  440. if( NODE_NEXT(np2) != NO_NODE )
  441. SET_NODE_PREV(NODE_NEXT(np2),np1);
  442. SET_NODE_NEXT(np1,NODE_NEXT(np2));
  443. SET_NODE_PREV(np2,NODE_PREV(np1));
  444. SET_NODE_NEXT(np2,np1);
  445. SET_NODE_PREV(np1,np2);
  446. } else {
  447. if( NODE_NEXT(np1) != NO_NODE )
  448. SET_NODE_PREV(NODE_NEXT(np1),np2);
  449. if( NODE_PREV(np1) != NO_NODE )
  450. SET_NODE_NEXT(NODE_PREV(np1),np2);
  451. if( NODE_NEXT(np2) != NO_NODE )
  452. SET_NODE_PREV(NODE_NEXT(np2),np1);
  453. if( NODE_PREV(np2) != NO_NODE )
  454. SET_NODE_NEXT(NODE_PREV(np2),np1);
  455. memcpy(tmp_np,np1,sizeof(Node));
  456. SET_NODE_NEXT(np1, NODE_NEXT(np2));
  457. SET_NODE_PREV(np1, NODE_PREV(np2));
  458. SET_NODE_NEXT(np2, NODE_NEXT(tmp_np));
  459. SET_NODE_PREV(np2, NODE_PREV(tmp_np));
  460. }
  461. if( QLIST_HEAD(lp) == np1 ) SET_QLIST_HEAD(lp,np2);
  462. else if( QLIST_HEAD(lp) == np2 ) SET_QLIST_HEAD(lp,np1);
  463. if( QLIST_TAIL(lp) == np1 ) SET_QLIST_TAIL(lp,np2);
  464. else if( QLIST_TAIL(lp) == np2 ) SET_QLIST_TAIL(lp,np1);
  465. UNLOCK_LIST(lp)
  466. }
  467. void p_sort( List* lp ) /** sort list with highest priority at head */
  468. {
  469. int done=0;
  470. Node *np;
  471. /* bubble sort */
  472. if( eltcount(lp) < 2 ) return;
  473. while( !done ){
  474. done=1;
  475. np=QLIST_HEAD(lp);
  476. while( NODE_NEXT(np) != NO_NODE && np!=QLIST_TAIL(lp) ){
  477. if( NODE_NEXT(np)->n_pri > np->n_pri ){
  478. /*
  479. sprintf(ERROR_STRING,"exchanging nodes w/ priorities %d, %d",
  480. NODE_NEXT(np)->n_pri,np->n_pri);
  481. NADVISE(ERROR_STRING);
  482. */
  483. l_exch( lp, np, NODE_NEXT(np) );
  484. done=0;
  485. } else {
  486. /*
  487. sprintf(ERROR_STRING,"leaving node w/ pri %d",np->n_pri);
  488. NADVISE(ERROR_STRING);
  489. */
  490. np=NODE_NEXT(np);
  491. }
  492. }
  493. }
  494. }
  495. Node *mk_node(void* dp) /** returns a node for a two-ended list */
  496. {
  497. Node *np;
  498. np=newnode();
  499. if( np == NO_NODE ) return(np);
  500. init_node(np,dp);
  501. return(np);
  502. }
  503. void init_node(Node *np,void* dp)
  504. {
  505. //#ifdef CAUTIOUS
  506. // if( np == NULL ){
  507. // NERROR1("CAUTIOUS: init_node: null node pointer!?");
  508. // IOS_RETURN
  509. // }
  510. //#endif // CAUTIOUS
  511. assert( np != NULL );
  512. np->n_data=dp;
  513. SET_NODE_NEXT(np,NO_NODE);
  514. SET_NODE_PREV(np,NO_NODE);
  515. np->n_pri = 0;
  516. }