int get_match_score(driver_t *drv, dev_node_t *dev) { link_t *drv_head = &drv->match_ids.ids.head; link_t *dev_head = &dev->pfun->match_ids.ids.head; if (list_empty(&drv->match_ids.ids) || list_empty(&dev->pfun->match_ids.ids)) { return 0; } /* * Go through all pairs, return the highest score obtained. */ int highest_score = 0; link_t *drv_link = drv->match_ids.ids.head.next; while (drv_link != drv_head) { link_t *dev_link = dev_head->next; while (dev_link != dev_head) { match_id_t *drv_id = list_get_instance(drv_link, match_id_t, link); match_id_t *dev_id = list_get_instance(dev_link, match_id_t, link); int score = compute_match_score(drv_id, dev_id); if (score > highest_score) { highest_score = score; } dev_link = dev_link->next; } drv_link = drv_link->next; } return highest_score; }
/** Get next ready segment from incoming queue. * * Return the segment with the earliest sequence number if it is ready. * A segment is ready if its SEG.SEQ is earlier or equal to RCV.NXT. * * @param iqueue Incoming queue * @param seg Place to store pointer to segment * @return EOK on success, ENOENT if no segment is ready */ int tcp_iqueue_get_ready_seg(tcp_iqueue_t *iqueue, tcp_segment_t **seg) { tcp_iqueue_entry_t *iqe; link_t *link; log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_get_ready_seg()"); link = list_first(&iqueue->list); if (link == NULL) { log_msg(LOG_DEFAULT, LVL_DEBUG, "iqueue is empty"); return ENOENT; } iqe = list_get_instance(link, tcp_iqueue_entry_t, link); while (!seq_no_segment_acceptable(iqueue->conn, iqe->seg)) { log_msg(LOG_DEFAULT, LVL_DEBUG, "Skipping unacceptable segment (RCV.NXT=%" PRIu32 ", RCV.NXT+RCV.WND=%" PRIu32 ", SEG.SEQ=%" PRIu32 ", SEG.LEN=%" PRIu32 ")", iqueue->conn->rcv_nxt, iqueue->conn->rcv_nxt + iqueue->conn->rcv_wnd, iqe->seg->seq, iqe->seg->len); list_remove(&iqe->link); tcp_segment_delete(iqe->seg); link = list_first(&iqueue->list); if (link == NULL) { log_msg(LOG_DEFAULT, LVL_DEBUG, "iqueue is empty"); return ENOENT; } iqe = list_get_instance(link, tcp_iqueue_entry_t, link); } /* Do not return segments that are not ready for processing */ if (!seq_no_segment_ready(iqueue->conn, iqe->seg)) { log_msg(LOG_DEFAULT, LVL_DEBUG, "Next segment not ready: SEG.SEQ=%u, " "RCV.NXT=%u, SEG.LEN=%u", iqe->seg->seq, iqueue->conn->rcv_nxt, iqe->seg->len); return ENOENT; } log_msg(LOG_DEFAULT, LVL_DEBUG, "Returning ready segment %p", iqe->seg); list_remove(&iqe->link); *seg = iqe->seg; free(iqe); return EOK; }
/** Cleanup the table of open files. */ static void vfs_files_done(vfs_client_data_t *vfs_data) { int i; if (!vfs_data->files) return; for (i = 0; i < MAX_OPEN_FILES; i++) { if (vfs_data->files[i]) (void) _vfs_fd_free(vfs_data, i); } free(vfs_data->files); while (!list_empty(&vfs_data->passed_handles)) { link_t *lnk; vfs_boxed_handle_t *bh; lnk = list_first(&vfs_data->passed_handles); list_remove(lnk); bh = list_get_instance(lnk, vfs_boxed_handle_t, link); free(bh); } }
/** Insert segment into incoming queue. * * @param iqueue Incoming queue * @param seg Segment */ void tcp_iqueue_insert_seg(tcp_iqueue_t *iqueue, tcp_segment_t *seg) { tcp_iqueue_entry_t *iqe; tcp_iqueue_entry_t *qe; link_t *link; log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_iqueue_insert_seg()"); iqe = calloc(1, sizeof(tcp_iqueue_entry_t)); if (iqe == NULL) { log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating IQE."); return; } iqe->seg = seg; /* Sort by sequence number */ link = list_first(&iqueue->list); while (link != NULL) { qe = list_get_instance(link, tcp_iqueue_entry_t, link); if (seq_no_seg_cmp(iqueue->conn, iqe->seg, qe->seg) >= 0) break; } if (link != NULL) list_insert_before(&iqe->link, &qe->link); else list_append(&iqe->link, &iqueue->list); }
void __stdio_done(void) { while (!list_empty(&files)) { FILE *file = list_get_instance(list_first(&files), FILE, link); fclose(file); } }
/** Get a received message. * * Pull one message from the association's receive queue. */ int udp_assoc_recv(udp_assoc_t *assoc, udp_msg_t **msg, udp_sock_t *fsock) { link_t *link; udp_rcv_queue_entry_t *rqe; log_msg(LVL_DEBUG, "udp_assoc_recv()"); fibril_mutex_lock(&assoc->lock); while (list_empty(&assoc->rcv_queue)) { log_msg(LVL_DEBUG, "udp_assoc_recv() - waiting"); fibril_condvar_wait(&assoc->rcv_queue_cv, &assoc->lock); } log_msg(LVL_DEBUG, "udp_assoc_recv() - got a message"); link = list_first(&assoc->rcv_queue); rqe = list_get_instance(link, udp_rcv_queue_entry_t, link); list_remove(link); fibril_mutex_unlock(&assoc->lock); *msg = rqe->msg; *fsock = rqe->sp.foreign; free(rqe); return EOK; }
/** Register clonable service. * * @param service Service to be registered. * @param phone Phone to be used for connections to the service. * @param call Pointer to call structure. * */ void register_clonable(sysarg_t service, sysarg_t phone, ipc_call_t *call, ipc_callid_t callid) { link_t *req_link; req_link = list_first(&cs_req); if (req_link == NULL) { /* There was no pending connection request. */ printf("%s: Unexpected clonable server.\n", NAME); ipc_answer_0(callid, EBUSY); return; } cs_req_t *csr = list_get_instance(req_link, cs_req_t, link); list_remove(req_link); /* Currently we can only handle a single type of clonable service. */ assert(csr->service == SERVICE_LOAD); ipc_answer_0(callid, EOK); ipc_forward_fast(csr->callid, phone, IPC_GET_ARG2(csr->call), IPC_GET_ARG3(csr->call), 0, IPC_FF_NONE); free(csr); ipc_hangup(phone); }
/** Allocate frame * * @param nic_data The NIC driver data * @param size Frame size in bytes * @return pointer to allocated frame if success, NULL otherwise */ nic_frame_t *nic_alloc_frame(nic_t *nic_data, size_t size) { nic_frame_t *frame; fibril_mutex_lock(&nic_globals.lock); if (nic_globals.frame_cache_size > 0) { link_t *first = list_first(&nic_globals.frame_cache); list_remove(first); nic_globals.frame_cache_size--; frame = list_get_instance(first, nic_frame_t, link); fibril_mutex_unlock(&nic_globals.lock); } else { fibril_mutex_unlock(&nic_globals.lock); frame = malloc(sizeof(nic_frame_t)); if (!frame) return NULL; link_initialize(&frame->link); } frame->data = malloc(size); if (frame->data == NULL) { free(frame); return NULL; } frame->size = size; return frame; }
/** Try to find a command beginning with prefix */ const char *cmdtab_enum(const char *name, const char **h, void **ctx) { link_t **startpos = (link_t**) ctx; size_t namelen = str_length(name); spinlock_lock(&cmd_lock); if (*startpos == NULL) *startpos = cmd_list.head.next; for (; *startpos != &cmd_list.head; *startpos = (*startpos)->next) { cmd_info_t *hlp = list_get_instance(*startpos, cmd_info_t, link); const char *curname = hlp->name; if (str_length(curname) < namelen) continue; if (str_lcmp(curname, name, namelen) == 0) { *startpos = (*startpos)->next; if (h) *h = hlp->description; spinlock_unlock(&cmd_lock); return (curname + str_lsize(curname, namelen)); } } spinlock_unlock(&cmd_lock); return NULL; }
/** Process pending wait requests */ void process_pending_wait(void) { task_exit_t texit; loop: list_foreach(pending_wait, cur) { pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link); unsigned long keys[2] = { LOWER32(pr->id), UPPER32(pr->id) }; link_t *link = hash_table_find(&task_hash_table, keys); if (!link) continue; hashed_task_t *ht = hash_table_get_instance(link, hashed_task_t, link); if (!ht->finished) continue; if (!(pr->callid & IPC_CALLID_NOTIFICATION)) { texit = ht->have_rval ? TASK_EXIT_NORMAL : TASK_EXIT_UNEXPECTED; ipc_answer_2(pr->callid, EOK, texit, ht->retval); } hash_table_remove(&task_hash_table, keys, 2); list_remove(cur); free(pr); goto loop; }
/* For each keyboard device */ list_foreach(kbd_devs, kdev_link) { kbd_dev_t *kdev = list_get_instance(kdev_link, kbd_dev_t, kbd_devs); /* Yield port */ if (kdev->port_ops != NULL) (*kdev->port_ops->yield)(); }
static slab_cache_t * slab_cache_alloc() { slab_t *slab; void *obj; u32_t *p; DBG("%s\n", __FUNCTION__); if (list_empty(&slab_cache_cache.partial_slabs)) { // spinlock_unlock(&cache->slablock); // slab = slab_create(); void *data; unsigned int i; data = (void*)(PA2KA(alloc_page())); if (!data) { return NULL; } slab = (slab_t*)((u32_t)data + PAGE_SIZE - sizeof(slab_t)); /* Fill in slab structures */ frame_set_parent(ADDR2PFN(KA2PA(data)), slab); slab->start = data; slab->available = slab_cache_cache.objects; slab->nextavail = (void*)data; slab->cache = &slab_cache_cache; for (i = 0,p = (u32_t*)slab->start;i < slab_cache_cache.objects; i++) { *p = (u32_t)p+slab_cache_cache.size; p = (u32_t*)((u32_t)p+slab_cache_cache.size); }; atomic_inc(&slab_cache_cache.allocated_slabs); // spinlock_lock(&cache->slablock); } else { slab = list_get_instance(slab_cache_cache.partial_slabs.next, slab_t, link); list_remove(&slab->link); } obj = slab->nextavail; slab->nextavail = *((void**)obj); slab->available--; if (!slab->available) list_prepend(&slab->link, &slab_cache_cache.full_slabs); else list_prepend(&slab->link, &slab_cache_cache.partial_slabs); // spinlock_unlock(&cache->slablock); return (slab_cache_t*)obj; }
/** Disconnects all phones connected to an answerbox. * * @param box Answerbox to disconnect phones from. * @param notify_box If true, the answerbox will get a hangup message for * each disconnected phone. * */ void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box) { phone_t *phone; DEADLOCK_PROBE_INIT(p_phonelck); call_t *call = notify_box ? ipc_call_alloc(0) : NULL; /* Disconnect all phones connected to our answerbox */ restart_phones: irq_spinlock_lock(&box->lock, true); while (!list_empty(&box->connected_phones)) { phone = list_get_instance(list_first(&box->connected_phones), phone_t, link); if (SYNCH_FAILED(mutex_trylock(&phone->lock))) { irq_spinlock_unlock(&box->lock, true); DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD); goto restart_phones; } /* Disconnect phone */ ASSERT(phone->state == IPC_PHONE_CONNECTED); list_remove(&phone->link); phone->state = IPC_PHONE_SLAMMED; if (notify_box) { mutex_unlock(&phone->lock); irq_spinlock_unlock(&box->lock, true); // FIXME: phone can become deallocated at any time now /* * Send one message to the answerbox for each * phone. Used to make sure the kbox thread * wakes up after the last phone has been * disconnected. */ IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP); call->request_method = IPC_M_PHONE_HUNGUP; call->flags |= IPC_CALL_DISCARD_ANSWER; _ipc_call(phone, box, call); /* Allocate another call in advance */ call = ipc_call_alloc(0); /* Must start again */ goto restart_phones; } mutex_unlock(&phone->lock); } irq_spinlock_unlock(&box->lock, true); /* Free unused call */ if (call) ipc_call_free(call); }
/** Add endpoint to the list and queue. * * @param[in] instance List to use. * @param[in] endpoint Endpoint to add. * * The endpoint is added to the end of the list and queue. */ void endpoint_list_add_ep(endpoint_list_t *instance, ohci_endpoint_t *ep) { assert(instance); assert(ep); usb_log_debug2("Queue %s: Adding endpoint(%p).\n", instance->name, ep); fibril_mutex_lock(&instance->guard); ed_t *last_ed = NULL; /* Add to the hardware queue. */ if (list_empty(&instance->endpoint_list)) { /* There are no active EDs */ last_ed = instance->list_head; } else { /* There are active EDs, get the last one */ ohci_endpoint_t *last = list_get_instance( list_last(&instance->endpoint_list), ohci_endpoint_t, link); last_ed = last->ed; } /* Keep link */ ep->ed->next = last_ed->next; /* Make sure ED is written to the memory */ write_barrier(); /* Add ed to the hw queue */ ed_append_ed(last_ed, ep->ed); /* Make sure ED is updated */ write_barrier(); /* Add to the sw list */ list_append(&ep->link, &instance->endpoint_list); ohci_endpoint_t *first = list_get_instance( list_first(&instance->endpoint_list), ohci_endpoint_t, link); usb_log_debug("HCD EP(%p) added to list %s, first is %p(%p).\n", ep, instance->name, first, first->ed); if (last_ed == instance->list_head) { usb_log_debug2("%s head ED(%p-0x%0" PRIx32 "): %x:%x:%x:%x.\n", instance->name, last_ed, instance->list_head_pa, last_ed->status, last_ed->td_tail, last_ed->td_head, last_ed->next); } fibril_mutex_unlock(&instance->guard); }
static void ipc_forget_all_active_calls(void) { call_t *call; restart: spinlock_lock(&TASK->active_calls_lock); if (list_empty(&TASK->active_calls)) { /* * We are done, there are no more active calls. * Nota bene: there may still be answers waiting for pick up. */ spinlock_unlock(&TASK->active_calls_lock); return; } call = list_get_instance(list_first(&TASK->active_calls), call_t, ta_link); if (!spinlock_trylock(&call->forget_lock)) { /* * Avoid deadlock and let async_answer() or * _ipc_answer_free_call() win the race to dequeue the first * call on the list. */ spinlock_unlock(&TASK->active_calls_lock); goto restart; } /* * Forget the call and donate it to the task which holds up the answer. */ call->forget = true; call->sender = NULL; list_remove(&call->ta_link); /* * The call may be freed by _ipc_answer_free_call() before we are done * with it; to avoid working with a destroyed call_t structure, we * must hold a reference to it. */ ipc_call_hold(call); spinlock_unlock(&call->forget_lock); spinlock_unlock(&TASK->active_calls_lock); atomic_dec(&call->caller_phone->active_calls); SYSIPC_OP(request_forget, call); ipc_call_release(call); goto restart; }
static unused_t *unused_find(service_id_t service_id, bool lock) { unused_t *u; if (lock) fibril_mutex_lock(&unused_lock); list_foreach(unused_list, l) { u = list_get_instance(l, unused_t, link); if (u->service_id == service_id) return u; }
static int fat_node_fini_by_service_id(service_id_t service_id) { fat_node_t *nodep; int rc; /* * We are called from fat_unmounted() and assume that there are already * no nodes belonging to this instance with non-zero refcount. Therefore * it is sufficient to clean up only the FAT free node list. */ restart: fibril_mutex_lock(&ffn_mutex); list_foreach(ffn_list, lnk) { nodep = list_get_instance(lnk, fat_node_t, ffn_link); if (!fibril_mutex_trylock(&nodep->lock)) { fibril_mutex_unlock(&ffn_mutex); goto restart; } if (!fibril_mutex_trylock(&nodep->idx->lock)) { fibril_mutex_unlock(&nodep->lock); fibril_mutex_unlock(&ffn_mutex); goto restart; } if (nodep->idx->service_id != service_id) { fibril_mutex_unlock(&nodep->idx->lock); fibril_mutex_unlock(&nodep->lock); continue; } list_remove(&nodep->ffn_link); fibril_mutex_unlock(&ffn_mutex); /* * We can unlock the node and its index structure because we are * the last player on this playground and VFS is preventing new * players from entering. */ fibril_mutex_unlock(&nodep->idx->lock); fibril_mutex_unlock(&nodep->lock); if (nodep->dirty) { rc = fat_node_sync(nodep); if (rc != EOK) return rc; } nodep->idx->nodep = NULL; free(nodep->bp); free(nodep); /* Need to restart because we changed ffn_list. */ goto restart; }
void sig_connect(signal_t *signal, widget_t *widget, slot_t slot) { fibril_rwlock_write_lock(&connection_guard); signal_node_t *sig_node = NULL; list_foreach(connection_list, link) { signal_node_t *cur = list_get_instance(link, signal_node_t, link); if (cur->signal == signal) { sig_node = cur; break; } }
/** * Some NICs can receive multiple frames during single interrupt. These can * send them in whole list of frames (actually nic_frame_t structures), then * the list is deallocated and each frame is passed to the * nic_received_packet function. * * @param nic_data * @param frames List of received frames */ void nic_received_frame_list(nic_t *nic_data, nic_frame_list_t *frames) { if (frames == NULL) return; while (!list_empty(frames)) { nic_frame_t *frame = list_get_instance(list_first(frames), nic_frame_t, link); list_remove(&frame->link); nic_received_frame(nic_data, frame); } nic_driver_release_frame_list(frames); }
static void srv_yield(ipc_callid_t iid, ipc_call_t *icall) { int ret = EOK; list_foreach(outdevs, link) { outdev_t *dev = list_get_instance(link, outdev_t, link); assert(dev->ops.yield); int rc = dev->ops.yield(dev); if (rc != EOK) ret = rc; }
/** List supported commands. * * @param argv Argument vector. * * @return 0 on failure, 1 on success. */ int cmd_help(cmd_arg_t *argv) { spinlock_lock(&cmd_lock); size_t len = 0; list_foreach(cmd_list, cur) { cmd_info_t *hlp; hlp = list_get_instance(cur, cmd_info_t, link); spinlock_lock(&hlp->lock); if (str_length(hlp->name) > len) len = str_length(hlp->name); spinlock_unlock(&hlp->lock); }
/** Destroy association structure. * * Association structure should be destroyed when the folowing conditions * are met: * (1) user has deleted the association * (2) nobody is holding references to the association * * This happens when @a assoc->refcnt is zero as we count (1) * as an extra reference. * * @param assoc Association */ static void udp_assoc_free(udp_assoc_t *assoc) { log_msg(LVL_DEBUG, "%s: udp_assoc_free(%p)", assoc->name, assoc); while (!list_empty(&assoc->rcv_queue)) { link_t *link = list_first(&assoc->rcv_queue); udp_rcv_queue_entry_t *rqe = list_get_instance(link, udp_rcv_queue_entry_t, link); list_remove(link); udp_msg_delete(rqe->msg); free(rqe); } free(assoc); }
/** Receive queue handler fibril. */ static int tcp_rqueue_fibril(void *arg) { link_t *link; tcp_rqueue_entry_t *rqe; log_msg(LVL_DEBUG, "tcp_rqueue_fibril()"); while (true) { link = prodcons_consume(&rqueue); rqe = list_get_instance(link, tcp_rqueue_entry_t, link); tcp_as_segment_arrived(&rqe->sp, rqe->seg); } /* Not reached */ return 0; }
int vfs_wait_handle_internal(void) { vfs_client_data_t *vfs_data = VFS_DATA; int fd; fibril_mutex_lock(&vfs_data->lock); while (list_empty(&vfs_data->passed_handles)) fibril_condvar_wait(&vfs_data->cv, &vfs_data->lock); link_t *lnk = list_first(&vfs_data->passed_handles); list_remove(lnk); fibril_mutex_unlock(&vfs_data->lock); vfs_boxed_handle_t *bh = list_get_instance(lnk, vfs_boxed_handle_t, link); fd = bh->handle; free(bh); return fd; }
static int inet_link_check_new(void) { bool already_known; category_id_t iplink_cat; service_id_t *svcs; size_t count, i; int rc; fibril_mutex_lock(&inet_discovery_lock); rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING); if (rc != EOK) { log_msg(LVL_ERROR, "Failed resolving category 'iplink'."); fibril_mutex_unlock(&inet_discovery_lock); return ENOENT; } rc = loc_category_get_svcs(iplink_cat, &svcs, &count); if (rc != EOK) { log_msg(LVL_ERROR, "Failed getting list of IP links."); fibril_mutex_unlock(&inet_discovery_lock); return EIO; } for (i = 0; i < count; i++) { already_known = false; list_foreach(inet_link_list, ilink_link) { inet_link_t *ilink = list_get_instance(ilink_link, inet_link_t, link_list); if (ilink->svc_id == svcs[i]) { already_known = true; break; } } if (!already_known) { log_msg(LVL_DEBUG, "Found IP link '%lu'", (unsigned long) svcs[i]); rc = inet_link_open(svcs[i]); if (rc != EOK) log_msg(LVL_ERROR, "Could not open IP link."); } }
/** Get instance from internal table by service_id. * * @param service_id Device identifier * @param inst Output instance if successful operation * * @return Error code * */ int ext4fs_instance_get(service_id_t service_id, ext4fs_instance_t **inst) { fibril_mutex_lock(&instance_list_mutex); if (list_empty(&instance_list)) { fibril_mutex_unlock(&instance_list_mutex); return EINVAL; } list_foreach(instance_list, link) { ext4fs_instance_t *tmp = list_get_instance(link, ext4fs_instance_t, link); if (tmp->service_id == service_id) { *inst = tmp; fibril_mutex_unlock(&instance_list_mutex); return EOK; } }
/** Find address object matching address @a addr. * * @param addr Address * @oaram find iaf_net to find network (using mask), * iaf_addr to find local address (exact match) */ inet_addrobj_t *inet_addrobj_find(inet_addr_t *addr, inet_addrobj_find_t find) { uint32_t mask; log_msg(LVL_DEBUG, "inet_addrobj_find(%x)", (unsigned)addr->ipv4); fibril_mutex_lock(&addr_list_lock); list_foreach(addr_list, link) { inet_addrobj_t *naddr = list_get_instance(link, inet_addrobj_t, addr_list); mask = inet_netmask(naddr->naddr.bits); if ((naddr->naddr.ipv4 & mask) == (addr->ipv4 & mask)) { fibril_mutex_unlock(&addr_list_lock); log_msg(LVL_DEBUG, "inet_addrobj_find: found %p", naddr); return naddr; } }
static void nodes_remove_callback(link_t *item) { tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t, nh_link); while (!list_empty(&nodep->cs_list)) { tmpfs_dentry_t *dentryp = list_get_instance( list_first(&nodep->cs_list), tmpfs_dentry_t, link); assert(nodep->type == TMPFS_DIRECTORY); list_remove(&dentryp->link); free(dentryp); } if (nodep->data) { assert(nodep->type == TMPFS_FILE); free(nodep->data); } free(nodep->bp); free(nodep); }
static void _fibril_condvar_wakeup_common(fibril_condvar_t *fcv, bool once) { link_t *tmp; awaiter_t *wdp; futex_down(&async_futex); while (!list_empty(&fcv->waiters)) { tmp = list_first(&fcv->waiters); wdp = list_get_instance(tmp, awaiter_t, wu_event.link); list_remove(&wdp->wu_event.link); wdp->wu_event.inlist = false; if (!wdp->active) { wdp->active = true; fibril_add_ready(wdp->fid); optimize_execution_power(); if (once) break; } } futex_up(&async_futex); }
/** Compare hash table element with a key. * * There are two things to note about this function. * First, it is used for the less complex architecture setup * in which there are not too many interrupt numbers (i.e. inr's) * to arrange the hash table so that collisions occur only * among same inrs of different devnos. So the explicit check * for inr match is not done. * Second, if devno is -1, the second key (i.e. devno) is not * used for the match and the result of the claim() function * is used instead. * * This function assumes interrupts are already disabled. * * @param key Keys (i.e. inr and devno). * @param keys This is 2. * @param item The item to compare the key with. * * @return True on match or false otherwise. * */ bool irq_lin_compare(sysarg_t key[], size_t keys, link_t *item) { irq_t *irq = list_get_instance(item, irq_t, link); devno_t devno = (devno_t) key[KEY_DEVNO]; bool rv; irq_spinlock_lock(&irq->lock, false); if (devno == -1) { /* Invoked by irq_dispatch_and_lock() */ rv = (irq->claim(irq) == IRQ_ACCEPT); } else { /* Invoked by irq_find_and_lock() */ rv = (irq->devno == devno); } /* unlock only on non-match */ if (!rv) irq_spinlock_unlock(&irq->lock, false); return rv; }