/* * Return 1 if the inserted event is closer in the future than any * others, 0 otherwise. */ static int __insert_event(struct thread_event *te, struct thread_event *events) { struct thread_event *tmp; assert(NULL != te); assert(te->event_expiration); assert(EMPTY_LIST(te, next, prev)); assert(events->next && events->prev); if (EMPTY_LIST(events, next, prev)) { ADD_LIST(events, te, next, prev); } else for (tmp = FIRST_LIST(events, next, prev) ; ; /* condition built into body (see break;) */ tmp = FIRST_LIST(tmp, next, prev)) { assert(tmp); struct thread_event *prev_te = LAST_LIST(tmp, next, prev); assert(prev_te); assert(tmp->prev && tmp->next); /* We found our place in the list OR end of list. * Either way, insert before this position */ if (tmp->event_expiration > te->event_expiration || events == tmp) { ADD_LIST(prev_te, te, next, prev); assert(prev_te->next == te && te->prev == prev_te); assert(te->next == tmp && tmp->prev == te); break; } assert(tmp->next && tmp->prev); } assert(!EMPTY_LIST(events, next, prev)); assert(!EMPTY_LIST(te, next, prev)); return 0; }
static void *alloc_rb_buff(rb_meta_t *r) { struct buff_page *p; int i; void *ret = NULL; lock_take(&r->l); if (EMPTY_LIST(&r->avail_pages, next, prev)) { if (NULL == (p = alloc_buff_page())) { lock_release(&r->l); return NULL; } ADD_LIST(&r->avail_pages, p, next, prev); } p = FIRST_LIST(&r->avail_pages, next, prev); assert(p->amnt_buffs < NP_NUM_BUFFS); for (i = 0 ; i < NP_NUM_BUFFS ; i++) { if (p->buff_used[i] == 0) { p->buff_used[i] = 1; ret = p->buffs[i]; p->amnt_buffs++; break; } } assert(NULL != ret); if (p->amnt_buffs == NP_NUM_BUFFS) { REM_LIST(p, next, prev); ADD_LIST(&r->used_pages, p, next, prev); } lock_release(&r->l); return ret; }
int search(unsigned char *p, int m, unsigned char *t, int n) { GList *pos, *z[SIGMA]; int i,j,k,count,first, hbc[SIGMA]; /* Preprocessing of the list */ BEGIN_PREPROCESSING for(i=0; i<SIGMA; i++) z[i]=NULL; if (p[0] == p[m-1]) for(i=0; i<SIGMA; i++) ADD_LIST(&z[i], 0); for(i=0; i<m-1;i++) if (p[i+1] == p[m-1]) ADD_LIST(&z[p[i]],(i+1)); /* Preprocessing of horspool bc */ for(i=0;i<SIGMA;i++) hbc[i]=m; for(i=0;i<m;i++) hbc[p[i]]=m-i-1; for(i=0;i<m;i++) t[n+i]=p[i]; END_PREPROCESSING /* searching */ BEGIN_SEARCHING count = 0; j = m-1; while (j<n) { while (k=hbc[t[j]]) j += k; { pos = z[t[j-1]]; while(pos!=NULL) { k = pos->k; i = 0; first = j-k; while(i<m && p[i]==t[first+i]) i++; if(i==m && first<=n-m) count++; pos = pos->next; } } j+=m; } END_SEARCHING return count; }
/* this function will be called upon a scheduled data collection for a specific rule. it has to write measurement values from 'flowdata' into 'buf' and set len accordingly */ int exportData( void **exp, int *len, void *flowdata ) { uint32_t i; packetData_t *pkt; flowRec_t *data = (flowRec_t *) flowdata; /* check if enough buffer space is available and reserve extra memory if not */ if (expSize < ROWSTRSIZE * (data->nrows + 1)) { uint8_t *newMemory = realloc(expData, ROWSTRSIZE * (data->nrows + 1)); if (newMemory != NULL) { expData = newMemory; expSize = ROWSTRSIZE * data->nrows; } else { /* not enough memory to write data to -> don't write data at all */ STARTEXPORT(expData); ADD_LIST(0); END_LIST(); ENDEXPORT(exp, len); return -1; } } STARTEXPORT(expData); ADD_LIST( data->nrows ); pkt = data->pkt; for (i = 0; i < data->nrows; i++) { ADD_UINT8( pkt->ipversion ); ADD_UINT8( pkt->ttl ); ADD_UINT16( pkt->pktlen ); ADD_UINT16( pkt->iphdrlen ); ADD_UINT16( pkt->proto ); ADD_UINT16( pkt->tcpudphdrlen ); ADD_STRING( pkt->srcip ); ADD_UINT16( pkt->srcport ); ADD_STRING( pkt->dstip ); ADD_UINT16( pkt->dstport ); ADD_UINT32( pkt->tcpseqno ); ADD_STRING( printFlags(pkt->tcpflags) ); pkt++; } END_LIST(); ENDEXPORT(exp, len); data->nrows = 0; return 0; }
static int fp_thread_params(struct sched_thd *t, char *p) { int prio, tmp; char curr = p[0]; struct sched_thd *c; assert(t); switch (curr) { case 'r': /* priority relative to current thread */ c = sched_get_current(); assert(c); tmp = atoi(&p[1]); prio = sched_get_metric(c)->priority + tmp; memcpy(sched_get_accounting(t), sched_get_accounting(c), sizeof(struct sched_accounting)); #ifdef DEFERRABLE if (sched_get_accounting(t)->T) ADD_LIST(&servers, t, sched_next, sched_prev); #endif if (prio > PRIO_LOWEST) prio = PRIO_LOWEST; break; case 'a': /* absolute priority */ prio = atoi(&p[1]); break; case 'i': /* idle thread */ prio = PRIO_LOWEST; break; case 't': /* timer thread */ prio = PRIO_HIGHEST; break; #ifdef DEFERRABLE case 'd': { prio = ds_parse_params(t, p); if (EMPTY_LIST(t, sched_next, sched_prev) && sched_get_accounting(t)->T) { ADD_LIST(&servers, t, sched_next, sched_prev); } fp_move_end_runnable(t); break; } #endif default: printc("unknown priority option @ %s, setting to low\n", p); prio = PRIO_LOW; } if (sched_thd_ready(t)) fp_rem_thd(t); fp_add_thd(t, prio); return 0; }
/*--------------------------------------*/ static struct rec_data_mm_list * rdmm_list_init(long id) { struct rec_data_mm_list *rdmm_list; /* FIXME: A BUG here that bitmap will be all 0 */ rdmm_list = cslab_alloc_rdmm_ls(); assert(rdmm_list); rdmm_list->id = id; rdmm_list->fcnt = fcounter; rdmm_list->recordable = 1; rdmm_list->head = rdmm_list->tail = &rdmm_list->first; if (cvect_add(&rec_mm_vect, rdmm_list, rdmm_list->id)) { printc("Cli: can not add list into cvect\n"); return NULL; } /* printc("Init a list using id %d (vect @ %p ", id,&rec_mm_vect); */ /* printc("list @ %p)\n", rdmm_list); */ #if (!LAZY_RECOVERY) INIT_LIST(rdmm_list, next, prev); if (!all_rdmm_list) { all_rdmm_list = cslab_alloc_rdmm_ls(); assert(all_rdmm_list); INIT_LIST(all_rdmm_list, next, prev); } else { ADD_LIST(all_rdmm_list, rdmm_list, next, prev); } #endif return rdmm_list; }
/* Return the top address of the page it is mapped into the * component */ static vaddr_t stkmgr_stk_add_to_spd(struct cos_stk_item *stk_item, struct spd_stk_info *info) { vaddr_t d_addr, stk_addr, ret; spdid_t d_spdid; assert(info && stk_item); assert(EMPTY_LIST(stk_item, next, prev)); d_spdid = info->spdid; // FIXME: Race condition ret = d_addr = (vaddr_t)valloc_alloc(cos_spd_id(), d_spdid, 1); /* d_addr = info->ci->cos_heap_ptr; */ /* info->ci->cos_heap_ptr += PAGE_SIZE; */ /* ret = info->ci->cos_heap_ptr; */ // DOUT("Setting flags and assigning flags\n"); stk_item->stk->flags = 0xDEADBEEF; stk_item->stk->next = (void *)0xDEADBEEF; stk_addr = (vaddr_t)(stk_item->hptr); if(d_addr != mman_alias_page(cos_spd_id(), stk_addr, d_spdid, d_addr)){ printc("<stkmgr>: Unable to map stack into component"); BUG(); } // DOUT("Mapped page\n"); stk_item->d_addr = d_addr; stk_item->parent_spdid = d_spdid; // Add stack to allocated stack array // DOUT("Adding to local spdid stk list\n"); ADD_LIST(&info->stk_list, stk_item, next, prev); info->num_allocated++; assert(info->num_allocated == stkmgr_num_alloc_stks(info->spdid)); return ret; }
/** * Asks for a stack back from all of the components. Will release and * take the lock. */ static void stkmgr_wait_for_stack(struct spd_stk_info *ssi) { struct blocked_thd *bthd; DOUT("stkmgr_request_stack\n"); stkmgr_spd_mark_relinquish(ssi->spdid); DOUT("All stacks for %d set to relinquish, %d waiting\n", ssi->spdid, cos_get_thd_id()); bthd = malloc(sizeof(struct blocked_thd)); if (bthd == NULL) BUG(); bthd->thd_id = cos_get_thd_id(); DOUT("Adding thd to the blocked list: %d\n", bthd->thd_id); ADD_LIST(&ssi->bthd_list, bthd, next, prev); ssi->num_blocked_thds++; RELEASE(); DOUT("Blocking thread: %d\n", bthd->thd_id); /* FIXME: dependencies */ sched_block(cos_spd_id(), 0); TAKE(); DOUT("Thd %d wokeup and is obtaining a stack\n", cos_get_thd_id()); return; }
static void init_spds(void) { int i, mgr; for (mgr = 0 ; mgr < NUM_TMEM_MGR ; mgr++) { INIT_LIST(&components[mgr], next, prev); for (i = 0 ; i < MAX_NUM_SPDS ; i++) { struct component *c; switch (mgr) { case STK_MGR: if (-1 == stkmgr_spd_concurrency_estimate(i)) continue; break; case CBUF_MGR: if (-1 == cbufmgr_spd_concurrency_estimate(i)) continue; break; default: BUG(); } c = malloc(sizeof(struct component)); if (!c) BUG(); memset(c, 0, sizeof(struct component)); c->spdid = i; c->allocated = DEFAULT_TMEM_AMNT; c->mgr = mgr; INIT_LIST(c, next, prev); ADD_LIST(&components[mgr], c, next, prev); ncomps++; } } }
static inline int __cbufp_alloc_slow(int cbid, int size, int *len, int *error) { int amnt = 0, i; cbuf_t cb; int *cbs; assert(cbid <= 0); if (cbid == 0) { struct cbuf_meta *cm; cbs = cbuf_alloc(PAGE_SIZE, &cb); assert(cbs); cbs[0] = 0; /* Do a garbage collection */ amnt = cbufp_collect(cos_spd_id(), size, cb); if (amnt < 0) { *error = 1; return -1; } CBUF_TAKE(); cbid = cbs[0]; /* own the cbuf we just collected */ if (amnt > 0) { cm = cbuf_vect_lookup_addr(cbid_to_meta_idx(cbid), 0); assert(cm); /* (should be atomic) */ cm->nfo.c.flags |= CBUFM_IN_USE | CBUFM_TOUCHED; } /* ...add the rest back into freelists */ for (i = 1 ; i < amnt ; i++) { struct cbuf_alloc_desc *d, *fl; struct cbuf_meta *meta; int idx = cbid_to_meta_idx(cbs[i]); u32_t page; void *data; assert(idx > 0); meta = cbuf_vect_lookup_addr(idx, 0); d = __cbuf_alloc_lookup(meta->nfo.c.ptr); assert(d && d->cbid == cbs[i]); fl = d->flhead; assert(fl); ADD_LIST(fl, d, next, prev); } CBUF_RELEASE(); cbuf_free(cbs); } /* Nothing collected...allocate a new cbufp! */ if (amnt == 0) { cbid = cbufp_create(cos_spd_id(), size, cbid*-1); if (cbid == 0) assert(0); } /* TODO update correctly */ *len = 1; return cbid; }
// track blocked threads here for all clients (on each thread stack) int __sg_sched_block(spdid_t spdid, int dependency_thd) { struct blocked_thd blk_thd; // add to list cos_sched_lock_take(); if (unlikely(!bthds[spdid].next)) { INIT_LIST(&bthds[spdid], next, prev); } INIT_LIST(&blk_thd, next, prev); blk_thd.id = cos_get_thd_id(); blk_thd.dep_thd = dependency_thd; /* printc("add to the list..... thd %d\n", cos_get_thd_id()); */ ADD_LIST(&bthds[spdid], &blk_thd, next, prev); cos_sched_lock_release(); sched_block(spdid, dependency_thd); // remove from list in both normal path and reflect path cos_sched_lock_take(); /* printc("remove from the list..... thd %d\n", cos_get_thd_id()); */ REM_LIST(&blk_thd, next, prev); cos_sched_lock_release(); return 0; }
static inline void fp_add_start_runnable(struct sched_thd *t) { struct sched_thd *head; u16_t p = sched_get_metric(t)->priority; assert(sched_thd_ready(t)); head = &priorities[p].runnable; ADD_LIST(head, t, prio_next, prio_prev); mask_set(p); }
static inline void fp_move_end_runnable(struct sched_thd *t) { struct sched_thd *head; unsigned short int p = sched_get_metric(t)->priority; assert(sched_thd_ready(t)); assert(!sched_thd_suspended(t)); head = &priorities[p].runnable; REM_LIST(t, prio_next, prio_prev); ADD_LIST(LAST_LIST(head, prio_next, prio_prev), t, prio_next, prio_prev); mask_set(p); }
static Layout_t * rsbml_build_doc_layout(SEXP r_layout) { Layout_t * layout; layout = Layout_create(); rsbml_build_doc_s_base((SBase_t *)layout, r_layout); SET_ATTR(Layout, layout, Id, id, STRING); // FIXME: libsml is missing Layout_setDimensions() /*Layout_setDimensions(layout, rsbml_build_doc_dimensions(GET_SLOT(r_layout, install("dimensions"))));*/ ADD_LIST(Layout, layout, CompartmentGlyph, compartmentGlyphs, compartment_glyph); ADD_LIST(Layout, layout, SpeciesGlyph, speciesGlyphs, species_glyph); ADD_LIST(Layout, layout, ReactionGlyph, reactionGlyphs, reaction_glyph); ADD_LIST(Layout, layout, TextGlyph, textGlyphs, text_glyph); ADD_LIST(Layout, layout, AdditionalGraphicalObject, additionalGraphicalObjects, graphical_object); return layout; }
/* insertion sort...only do once */ static int insert_thread(struct thd *t) { struct thd *iter; for (iter = FIRST_LIST(&threads, next, prev) ; iter->sched_info.priority < t->sched_info.priority && iter != &threads ; iter = FIRST_LIST(iter, next, prev)); ADD_LIST(LAST_LIST(iter, next, prev), t, next, prev); return 0; }
static Curve_t * rsbml_build_doc_curve(SEXP r_curve) { Curve_t * curve; curve = Curve_create(); rsbml_build_doc_s_base((SBase_t *)curve, r_curve); ADD_LIST(Curve, curve, CurveSegment, curveSegments, line_segment); return curve; }
static Reaction_t * rsbml_build_doc_reaction(SEXP r_reaction) { Reaction_t * reaction; SEXP kineticLaw = GET_SLOT(r_reaction, install("kineticLaw")); reaction = Reaction_create(); rsbml_build_doc_s_base((SBase_t *)reaction, r_reaction); SET_ATTR(Reaction, reaction, Id, id, STRING); SET_ATTR(Reaction, reaction, Name, name, STRING); ADD_LIST(Reaction, reaction, Reactant, reactants, species_reference); ADD_LIST(Reaction, reaction, Product, products, species_reference); ADD_LIST(Reaction, reaction, Modifier, modifiers, modifier_species_reference); if (GET_LENGTH(kineticLaw)) Reaction_setKineticLaw(reaction, rsbml_build_doc_kinetic_law(kineticLaw)); SET_ATTR(Reaction, reaction, Reversible, reversible, LOGICAL); SET_ATTR(Reaction, reaction, Fast, fast, LOGICAL); return reaction; }
static inline void cbuf_thread_block(struct cbuf_comp_info *cci, unsigned long request_size) { struct blocked_thd bthd; bthd.thd_id = cos_get_thd_id(); bthd.request_size = request_size; rdtscll(bthd.blk_start); ADD_LIST(&cci->bthd_list, &bthd, next, prev); cci->num_blocked_thds++; cbuf_mark_relinquish_all(cci); CBUF_RELEASE(); sched_block(cos_spd_id(), 0); }
int cbufp_retrieve(spdid_t spdid, int cbid, int len) { struct cbufp_comp_info *cci; struct cbufp_info *cbi; struct cbuf_meta *meta; struct cbufp_maps *map; vaddr_t dest; void *page; int ret = -1; CBUFP_TAKE(); cci = cbufp_comp_info_get(spdid); if (!cci) goto done; cbi = cmap_lookup(&cbufs, cbid); if (!cbi) goto done; /* shouldn't cbuf2buf your own buffer! */ if (cbi->owner.spdid == spdid) goto done; meta = cbufp_meta_lookup(cci, cbid); if (!meta) goto done; map = malloc(sizeof(struct cbufp_maps)); if (!map) goto done; dest = (vaddr_t)valloc_alloc(cos_spd_id(), spdid, 1); if (!dest) goto free; map->spdid = spdid; map->m = meta; map->addr = dest; INIT_LIST(map, next, prev); ADD_LIST(&cbi->owner, map, next, prev); page = cbi->mem; assert(page); if (dest != (mman_alias_page(cos_spd_id(), (vaddr_t)page, spdid, dest))) { assert(0); valloc_free(cos_spd_id(), spdid, (void *)dest, 1); } meta->nfo.c.flags |= CBUFM_TOUCHED; meta->nfo.c.ptr = map->addr >> PAGE_ORDER; ret = 0; done: CBUFP_RELEASE(); return ret; free: free(map); goto done; }
static UnitDefinition_t * rsbml_build_doc_unit_definition(SEXP r_unit_definition) { UnitDefinition_t * unit_definition; unit_definition = UnitDefinition_create(); rsbml_build_doc_s_base((SBase_t *)unit_definition, r_unit_definition); SET_ATTR(UnitDefinition, unit_definition, Id, id, STRING); SET_ATTR(UnitDefinition, unit_definition, Name, name, STRING); ADD_LIST(UnitDefinition, unit_definition, Unit, units, unit); return unit_definition; }
static void mapping_init(struct mapping *m, spdid_t spdid, vaddr_t a, struct mapping *p, struct frame *f) { assert(m && f); INIT_LIST(m, _s, s_); m->f = f; m->flags = 0; m->spdid = spdid; m->addr = a; m->p = p; if (p) { m->flags = p->flags; if (!p->c) p->c = m; else ADD_LIST(p->c, m, _s, s_); } }
static KineticLaw_t * rsbml_build_doc_kinetic_law(SEXP r_kinetic_law) { KineticLaw_t * kinetic_law; kinetic_law = KineticLaw_create(); rsbml_build_doc_s_base((SBase_t *)kinetic_law, r_kinetic_law); SET_ATTR(KineticLaw, kinetic_law, Math, math, EXPRESSION); ADD_LIST(KineticLaw, kinetic_law, Parameter, parameters, parameter); SET_ATTR(KineticLaw, kinetic_law, TimeUnits, timeUnits, STRING); SET_ATTR(KineticLaw, kinetic_law, SubstanceUnits, substanceUnits, STRING); return kinetic_law; }
static Model_t * rsbml_build_doc_model(SEXP r_model) { Model_t *model = Model_create(); SET_ATTR(Model, model, Id, id, STRING); SET_ATTR(Model, model, Name, name, STRING); ADD_LIST(Model, model, Species, species, species); ADD_LIST(Model, model, FunctionDefinition, functionDefinitions, function_definition); ADD_LIST(Model, model, UnitDefinition, unitDefinitions, unit_definition); ADD_LIST(Model, model, Compartment, compartments, compartment); ADD_LIST(Model, model, Parameter, parameters, parameter); ADD_LIST(Model, model, Rule, rules, rule); ADD_LIST(Model, model, Reaction, reactions, reaction); ADD_LIST(Model, model, Event, events, event); #ifdef USE_LAYOUT ADD_LIST(Model, model, Layout, layouts, layout); #endif return model; }
static Event_t * rsbml_build_doc_event(SEXP r_event) { Event_t * event; event = Event_create(); rsbml_build_doc_s_base((SBase_t *)event, r_event); SET_ATTR(Event, event, Id, id, STRING); SET_ATTR(Event, event, Name, name, STRING); SET_ATTR(Event, event, Trigger, trigger, EXPRESSION); SET_ATTR(Event, event, Delay, delay, EXPRESSION); SET_ATTR(Event, event, TimeUnits, timeUnits, STRING); ADD_LIST(Event, event, EventAssignment, eventAssignments, event_assignment); return event; }
static struct cbuf_meta_range * cbuf_meta_add(struct cbuf_comp_info *comp, unsigned int cbid, struct cbuf_meta *m, vaddr_t dest) { struct cbuf_meta_range *cmr; if (cbuf_meta_lookup(comp, cbid)) return NULL; cmr = malloc(sizeof(struct cbuf_meta_range)); if (unlikely(!cmr)) return NULL; INIT_LIST(cmr, next, prev); cmr->m = m; cmr->dest = dest; cmr->low_id = round_to_pow2(cbid, PAGE_SIZE/sizeof(struct cbuf_meta)); if (comp->cbuf_metas) ADD_LIST(comp->cbuf_metas, cmr, next, prev); else comp->cbuf_metas = cmr; return cmr; }
static void parent_rd_cons(struct rec_data_mm *rd, vaddr_t s_addr) { assert(rd && s_addr); struct parent_rec_data_mm *parent_rd = NULL; parent_rd = parent_rdmm_lookup(s_addr); if (!parent_rd) { parent_rd = parent_rdmm_alloc(s_addr); assert(parent_rd); parent_rd->head = rd; } else { assert(parent_rd && parent_rd->head); ADD_LIST(parent_rd->head, rd, next, prev); } return; }
static ReactionGlyph_t * rsbml_build_doc_reaction_glyph(SEXP r_reaction_glyph) { ReactionGlyph_t * reaction_glyph; SEXP r_curve = GET_SLOT(r_reaction_glyph, install("curve")); reaction_glyph = ReactionGlyph_create(); rsbml_build_doc_base_graphical_object((GraphicalObject_t *)reaction_glyph, r_reaction_glyph); SET_ATTR(ReactionGlyph, reaction_glyph, ReactionId, reaction, STRING); if (GET_LENGTH(r_curve)) ReactionGlyph_setCurve(reaction_glyph, rsbml_build_doc_curve(r_curve)); ADD_LIST(ReactionGlyph, reaction_glyph, SpeciesReferenceGlyph, speciesReferenceGlyphs, species_reference_glyph); return reaction_glyph; }
static struct cbufp_meta_range * cbufp_meta_add(struct cbufp_comp_info *comp, u32_t cbid, struct cbuf_meta *m, vaddr_t dest) { struct cbufp_meta_range *cmr; if (cbufp_meta_lookup(comp, cbid)) return NULL; cmr = malloc(sizeof(struct cbufp_meta_range)); if (!cmr) return NULL; INIT_LIST(cmr, next, prev); cmr->m = m; cmr->dest = dest; /* must be power of 2: */ cmr->low_id = (cbid & ~((PAGE_SIZE/sizeof(struct cbuf_meta))-1)); if (comp->cbuf_metas) ADD_LIST(comp->cbuf_metas, cmr, next, prev); else comp->cbuf_metas = cmr; return cmr; }
static inline int __spd_cbvect_add_range(struct spd_tmem_info *sti, long cbuf_id, vaddr_t page) { struct spd_cbvect_range *cbr; cbr = malloc(sizeof(struct spd_cbvect_range)); if (!cbr) return -1; cbr->start_id = (cbuf_id - 1) & ~CBUF_VECT_MASK; cbr->end_id = cbr->start_id + CBUF_VECT_PAGE_BASE - 1; cbr->meta = (union cbuf_meta*)page; /* DOUT("spd %d sti %p cbr->meta %p\n",sti->spdid,sti, cbr->meta); */ ADD_LIST(&sti->ci, cbr, next, prev); /* DOUT("range is added here:: startid %ld endid %ld\n", cbr->start_id, cbr->end_id); */ return 0; }
/* Take all decedents, return them in a list. */ static struct mapping * __mapping_linearize_decendents(struct mapping *m) { struct mapping *first, *last, *c, *gc; first = c = m->c; m->c = NULL; if (!c) return NULL; do { last = LAST_LIST(first, _s, s_); c->p = NULL; gc = c->c; c->c = NULL; /* add the grand-children onto the end of our list of decedents */ if (gc) ADD_LIST(last, gc, _s, s_); c = FIRST_LIST(c, _s, s_); } while (first != c); return first; }