X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_eal%2Flinux%2Feal%2Feal_interrupts.c;h=be0dd4490b65bf3545c40b90d4fa25f001fb74be;hb=6e48cf0369c1906109918b3b7975b23648cf5ad4;hp=cbac451e113c4ada97a6e01743f6851272b3963c;hpb=91d7846ce68d7c637cd7efde751f5276475aa9c8;p=dpdk.git diff --git a/lib/librte_eal/linux/eal/eal_interrupts.c b/lib/librte_eal/linux/eal/eal_interrupts.c index cbac451e11..be0dd4490b 100644 --- a/lib/librte_eal/linux/eal/eal_interrupts.c +++ b/lib/librte_eal/linux/eal/eal_interrupts.c @@ -76,6 +76,8 @@ struct rte_intr_callback { TAILQ_ENTRY(rte_intr_callback) next; rte_intr_callback_fn cb_fn; /**< callback address */ void *cb_arg; /**< parameter for callback */ + uint8_t pending_delete; /**< delete after callback is called */ + rte_intr_unregister_callback_fn ucb_fn; /**< fn to call before cb is deleted */ }; struct rte_intr_source { @@ -472,6 +474,8 @@ rte_intr_callback_register(const struct rte_intr_handle *intr_handle, } callback->cb_fn = cb; callback->cb_arg = cb_arg; + callback->pending_delete = 0; + callback->ucb_fn = NULL; rte_spinlock_lock(&intr_lock); @@ -518,6 +522,57 @@ rte_intr_callback_register(const struct rte_intr_handle *intr_handle, return ret; } +int __rte_experimental +rte_intr_callback_unregister_pending(const struct rte_intr_handle *intr_handle, + rte_intr_callback_fn cb_fn, void *cb_arg, + rte_intr_unregister_callback_fn ucb_fn) +{ + int ret; + struct rte_intr_source *src; + struct rte_intr_callback *cb, *next; + + /* do parameter checking first */ + if (intr_handle == NULL || intr_handle->fd < 0) { + RTE_LOG(ERR, EAL, + "Unregistering with invalid input parameter\n"); + return -EINVAL; + } + + rte_spinlock_lock(&intr_lock); + + /* check if the insterrupt source for the fd is existent */ + TAILQ_FOREACH(src, &intr_sources, next) + if (src->intr_handle.fd == intr_handle->fd) + break; + + /* No interrupt source registered for the fd */ + if (src == NULL) { + ret = -ENOENT; + + /* only usable if the source is active */ + } else if (src->active == 0) { + ret = -EAGAIN; + + } else { + ret = 0; + + /* walk through the callbacks and mark all that match. */ + for (cb = TAILQ_FIRST(&src->callbacks); cb != NULL; cb = next) { + next = TAILQ_NEXT(cb, next); + if (cb->cb_fn == cb_fn && (cb_arg == (void *)-1 || + cb->cb_arg == cb_arg)) { + cb->pending_delete = 1; + cb->ucb_fn = ucb_fn; + ret++; + } + } + } + + rte_spinlock_unlock(&intr_lock); + + return ret; +} + int rte_intr_callback_unregister(const struct rte_intr_handle *intr_handle, rte_intr_callback_fn cb_fn, void *cb_arg) @@ -698,7 +753,7 @@ static int eal_intr_process_interrupts(struct epoll_event *events, int nfds) { bool call = false; - int n, bytes_read; + int n, bytes_read, rv; struct rte_intr_source *src; struct rte_intr_callback *cb, *next; union rte_intr_read_buffer buf; @@ -823,9 +878,35 @@ eal_intr_process_interrupts(struct epoll_event *events, int nfds) rte_spinlock_lock(&intr_lock); } } - /* we done with that interrupt source, release it. */ src->active = 0; + + rv = 0; + + /* check if any callback are supposed to be removed */ + for (cb = TAILQ_FIRST(&src->callbacks); cb != NULL; cb = next) { + next = TAILQ_NEXT(cb, next); + if (cb->pending_delete) { + TAILQ_REMOVE(&src->callbacks, cb, next); + if (cb->ucb_fn) + cb->ucb_fn(&src->intr_handle, cb->cb_arg); + free(cb); + rv++; + } + } + + /* all callbacks for that source are removed. */ + if (TAILQ_EMPTY(&src->callbacks)) { + TAILQ_REMOVE(&intr_sources, src, next); + free(src); + } + + /* notify the pipe fd waited by epoll_wait to rebuild the wait list */ + if (rv >= 0 && write(intr_pipe.writefd, "1", 1) < 0) { + rte_spinlock_unlock(&intr_lock); + return -EPIPE; + } + rte_spinlock_unlock(&intr_lock); }