int LNetEQAlloc(unsigned int count, lnet_eq_handler_t callback, lnet_handle_eq_t *handle) { lnet_eq_t *eq; LASSERT (the_lnet.ln_init); LASSERT (the_lnet.ln_refcount > 0); /* We need count to be a power of 2 so that when eq_{enq,deq}_seq * overflow, they don't skip entries, so the queue has the same * apparant capacity at all times */ if (count != LOWEST_BIT_SET(count)) { /* not a power of 2 already */ do { /* knock off all but the top bit... */ count &= ~LOWEST_BIT_SET (count); } while (count != LOWEST_BIT_SET(count)); count <<= 1; /* ...and round up */ } if (count == 0) /* catch bad parameter / overflow on roundup */ return (-EINVAL); eq = lnet_eq_alloc(); if (eq == NULL) return (-ENOMEM); LIBCFS_ALLOC(eq->eq_events, count * sizeof(lnet_event_t)); if (eq->eq_events == NULL) { LNET_LOCK(); lnet_eq_free (eq); LNET_UNLOCK(); return -ENOMEM; } /* NB this resets all event sequence numbers to 0, to be earlier * than eq_deq_seq */ memset(eq->eq_events, 0, count * sizeof(lnet_event_t)); eq->eq_deq_seq = 1; eq->eq_enq_seq = 1; eq->eq_size = count; eq->eq_refcount = 0; eq->eq_callback = callback; LNET_LOCK(); lnet_initialise_handle (&eq->eq_lh, LNET_COOKIE_TYPE_EQ); list_add (&eq->eq_list, &the_lnet.ln_active_eqs); LNET_UNLOCK(); lnet_eq2handle(handle, eq); return (0); }
extern uthread_struct_t *sched_find_best_uthread(kthread_runqueue_t *kthread_runq) { /* [1] Tries to find the highest priority RUNNABLE uthread in active-runq. * [2] Found - Jump to [FOUND] * [3] Switches runqueues (active/expires) * [4] Repeat [1] through [2] * [NOT FOUND] Return NULL(no more jobs) * [FOUND] Remove uthread from pq and return it. */ runqueue_t *runq; prio_struct_t *prioq; uthread_head_t *u_head; uthread_struct_t *u_obj; unsigned int uprio, ugroup; gt_spin_lock(&(kthread_runq->kthread_runqlock)); runq = kthread_runq->active_runq; kthread_runq->kthread_runqlock.holder = 0x04; if(!(runq->uthread_mask)) { /* No jobs in active. switch runqueue */ assert(!runq->uthread_tot); kthread_runq->active_runq = kthread_runq->expires_runq; kthread_runq->expires_runq = runq; runq = kthread_runq->expires_runq; if(!runq->uthread_mask) { assert(!runq->uthread_tot); gt_spin_unlock(&(kthread_runq->kthread_runqlock)); return NULL; } } /* Find the highest priority bucket */ uprio = LOWEST_BIT_SET(runq->uthread_mask); prioq = &(runq->prio_array[uprio]); assert(prioq->group_mask); ugroup = LOWEST_BIT_SET(prioq->group_mask); u_head = &(prioq->group[ugroup]); u_obj = TAILQ_FIRST(u_head); __rem_from_runqueue(runq, u_obj); gt_spin_unlock(&(kthread_runq->kthread_runqlock)); #if U_DEBUG printf("cpu(%d) : sched best uthread(id:%d, group:%d)\n", u_obj->cpu_id, u_obj->uthread_tid, u_obj->uthread_gid); #endif return(u_obj); }
extern uthread_struct_t *sched_find_best_uthread_group(kthread_runqueue_t *kthread_runq) { #if 0 /* [1] Tries to find a RUNNABLE uthread in active-runq from u_gid. * [2] Found - Jump to [FOUND] * [3] Tries to find a thread from a group with least threads in runq (XXX: NOT DONE) * - [Tries to find the highest priority RUNNABLE thread (XXX: DONE)] * [4] Found - Jump to [FOUND] * [5] Switches runqueues (active/expires) * [6] Repeat [1] through [4] * [NOT FOUND] Return NULL(no more jobs) * [FOUND] Remove uthread from pq and return it. */ runqueue_t *runq; prio_struct_t *prioq; uthread_head_t *u_head; uthread_struct_t *u_obj; unsigned int uprio, ugroup, mask; uthread_group_t u_gid; #ifndef COSCHED return sched_find_best_uthread(kthread_runq); #endif /* XXX: Read u_gid from global uthread-select-criterion */ u_gid = 0; runq = kthread_runq->active_runq; if(!runq->uthread_mask) { /* No jobs in active. switch runqueue */ assert(!runq->uthread_tot); kthread_runq->active_runq = kthread_runq->expires_runq; kthread_runq->expires_runq = runq; runq = kthread_runq->expires_runq; if(!runq->uthread_mask) { assert(!runq->uthread_tot); return NULL; } } if(!(mask = runq->uthread_group_mask[u_gid])) { /* No uthreads in the desired group */ assert(!runq->uthread_group_tot[u_gid]); return (sched_find_best_uthread(kthread_runq)); } /* Find the highest priority bucket for u_gid */ uprio = LOWEST_BIT_SET(mask); /* Take out a uthread from the bucket. Return it. */ u_head = &(runq->prio_array[uprio].group[u_gid]); u_obj = TAILQ_FIRST(u_head); rem_from_runqueue(runq, &(kthread_runq->kthread_runqlock), u_obj); return(u_obj); #endif return (uthread_struct_t * )NULL; }
/* [1] Tries to find the highest priority RUNNABLE uthread in active-runq. * [2] Found - Jump to [FOUND] * [3] Switches runqueues (active/expires) * [4] Repeat [1] through [2] * [NOT FOUND] Return NULL(no more jobs) * [FOUND] Remove uthread from pq and return it. */ uthread_t *pcs_pick_next_uthread(kthread_t *k_ctx) { checkpoint("k%d: PCS: Picking next uthread", k_ctx->cpuid); pcs_kthread_t *pcs_kthread = pcs_get_kthread(k_ctx); kthread_runqueue_t *kthread_runq = &pcs_kthread->k_runqueue; gt_spin_lock(&(kthread_runq->kthread_runqlock)); kthread_runq->kthread_runqlock.holder = 0x04; runqueue_t *runq = kthread_runq->active_runq; if (!(runq->uthread_mask)) { /* No jobs in active. switch runqueue */ checkpoint("k%d: PCS: Switching runqueues", k_ctx->cpuid); assert(!runq->uthread_tot); kthread_runq->active_runq = kthread_runq->expires_runq; kthread_runq->expires_runq = runq; runq = kthread_runq->active_runq; if (!runq->uthread_mask) { assert(!runq->uthread_tot); gt_spin_unlock(&(kthread_runq->kthread_runqlock)); return NULL; } } /* Find the highest priority bucket */ unsigned int uprio, ugroup; uprio = LOWEST_BIT_SET(runq->uthread_mask); prio_struct_t *prioq = &(runq->prio_array[uprio]); assert(prioq->group_mask); ugroup = LOWEST_BIT_SET(prioq->group_mask); uthread_head_t *u_head = &(prioq->group[ugroup]); pcs_uthread_t *next_uthread = TAILQ_FIRST(u_head); rem_from_runqueue(runq, NULL, next_uthread); gt_spin_unlock(&(kthread_runq->kthread_runqlock)); return next_uthread->uthread; }
void lnet_enq_event_locked (lnet_eq_t *eq, lnet_event_t *ev) { lnet_event_t *eq_slot; /* Allocate the next queue slot */ ev->sequence = eq->eq_enq_seq++; /* size must be a power of 2 to handle sequence # overflow */ LASSERT (eq->eq_size != 0 && eq->eq_size == LOWEST_BIT_SET (eq->eq_size)); eq_slot = eq->eq_events + (ev->sequence & (eq->eq_size - 1)); /* There is no race since both event consumers and event producers * take the LNET_LOCK, so we don't screw around with memory * barriers, setting the sequence number last or wierd structure * layout assertions. */ *eq_slot = *ev; /* Call the callback handler (if any) */ if (eq->eq_callback != NULL) eq->eq_callback (eq_slot); #ifdef __KERNEL__ /* Wake anyone waiting in LNetEQPoll() */ if (cfs_waitq_active(&the_lnet.ln_waitq)) cfs_waitq_broadcast(&the_lnet.ln_waitq); #else # ifndef HAVE_LIBPTHREAD /* LNetEQPoll() calls into _the_ LND to wait for action */ # else /* Wake anyone waiting in LNetEQPoll() */ pthread_cond_broadcast(&the_lnet.ln_cond); # endif #endif }