Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/netmap/netmap_freebsd.c
Show First 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
mtx_init(m, "nm_kn_lock", NULL, MTX_DEF); | mtx_init(m, "nm_kn_lock", NULL, MTX_DEF); | ||||
knlist_init_mtx(&si->si.si_note, m); | knlist_init_mtx(&si->si.si_note, m); | ||||
} | } | ||||
void | void | ||||
nm_os_selinfo_uninit(NM_SELINFO_T *si) | nm_os_selinfo_uninit(NM_SELINFO_T *si) | ||||
{ | { | ||||
/* XXX kqueue(9) needed; these will mirror knlist_init. */ | /* XXX kqueue(9) needed; these will mirror knlist_init. */ | ||||
knlist_delete(&si->si.si_note, curthread, 0 /* not locked */ ); | knlist_delete(&si->si.si_note, curthread, /*islocked=*/0); | ||||
knlist_destroy(&si->si.si_note); | knlist_destroy(&si->si.si_note); | ||||
/* now we don't need the mutex anymore */ | /* now we don't need the mutex anymore */ | ||||
mtx_destroy(&si->m); | mtx_destroy(&si->m); | ||||
} | } | ||||
void * | void * | ||||
nm_os_malloc(size_t size) | nm_os_malloc(size_t size) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | |||||
nm_os_kctx_worker_stop(nmk); | nm_os_kctx_worker_stop(nmk); | ||||
free(nmk, M_DEVBUF); | free(nmk, M_DEVBUF); | ||||
} | } | ||||
/******************** kqueue support ****************/ | /******************** kqueue support ****************/ | ||||
/* | /* | ||||
* nm_os_selwakeup also needs to issue a KNOTE_UNLOCKED. | * In addition to calling selwakeuppri(), nm_os_selwakeup() also | ||||
afedorov: I think the comment should be updated. | |||||
* We use a non-zero argument to distinguish the call from the one | * needs to call KNOTE to wake up kqueue listeners. | ||||
* in kevent_scan() which instead also needs to run netmap_poll(). | * We use a non-zero 'hint' argument to inform the netmap_knrw() | ||||
* The knote uses a global mutex for the time being. We might | * function that it is being called from 'nm_os_selwakeup'; this | ||||
* try to reuse the one in the si, but it is not allocated | * is necessary because when netmap_knrw() is called by the kevent | ||||
* permanently so it might be a bit tricky. | * subsystem (i.e. kevent_scan()) we also need to call netmap_poll(). | ||||
* The knote uses a private mutex associated to the 'si' (see struct | |||||
* selinfo, struct nm_selinfo, and nm_os_selinfo_init). | |||||
* | * | ||||
* The *kqfilter function registers one or another f_event | * The netmap_kqfilter() function registers one or another f_event | ||||
* depending on read or write mode. | * depending on read or write mode. A pointer to the struct | ||||
* In the call to f_event() td_fpop is NULL so any child function | * 'netmap_priv_d' is stored into kn->kn_hook, so that it can later | ||||
* calling devfs_get_cdevpriv() would fail - and we need it in | * be passed to netmap_poll(). We pass NULL as a third argument to | ||||
* netmap_poll(). As a workaround we store priv into kn->kn_hook | * netmap_poll(), so that the latter only runs the txsync/rxsync | ||||
* and pass it as first argument to netmap_poll(), which then | * (if necessary), and skips the nm_os_selrecord() calls. | ||||
* uses the failure to tell that we are called from f_event() | |||||
* and do not need the selrecord(). | |||||
*/ | */ | ||||
void | void | ||||
nm_os_selwakeup(struct nm_selinfo *si) | nm_os_selwakeup(struct nm_selinfo *si) | ||||
{ | { | ||||
if (netmap_verbose) | if (netmap_verbose) | ||||
D("on knote %p", &si->si.si_note); | nm_prinf("on knote %p", &si->si.si_note); | ||||
selwakeuppri(&si->si, PI_NET); | selwakeuppri(&si->si, PI_NET); | ||||
/* use a non-zero hint to tell the notification from the | /* We use a non-zero hint to distinguish this notification call | ||||
* call done in kqueue_scan() which uses 0 | * from the call done in kqueue_scan(), which uses hint=0. | ||||
*/ | */ | ||||
KNOTE_UNLOCKED(&si->si.si_note, 0x100 /* notification */); | KNOTE(&si->si.si_note, /*hint=*/0x100, | ||||
mtx_owned(&si->m) ? KNF_LISTLOCKED : 0); | |||||
markjUnsubmitted Done Inline ActionsIndentation should be by four spaces. markj: Indentation should be by four spaces. | |||||
} | } | ||||
void | void | ||||
nm_os_selrecord(struct thread *td, struct nm_selinfo *si) | nm_os_selrecord(struct thread *td, struct nm_selinfo *si) | ||||
{ | { | ||||
selrecord(td, &si->si); | selrecord(td, &si->si); | ||||
} | } | ||||
static void | static void | ||||
netmap_knrdetach(struct knote *kn) | netmap_knrdetach(struct knote *kn) | ||||
{ | { | ||||
struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook; | struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook; | ||||
struct selinfo *si = &priv->np_si[NR_RX]->si; | struct selinfo *si = &priv->np_si[NR_RX]->si; | ||||
D("remove selinfo %p", si); | D("remove selinfo %p", si); | ||||
knlist_remove(&si->si_note, kn, 0); | knlist_remove(&si->si_note, kn, /*islocked=*/0); | ||||
} | } | ||||
static void | static void | ||||
netmap_knwdetach(struct knote *kn) | netmap_knwdetach(struct knote *kn) | ||||
{ | { | ||||
struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook; | struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook; | ||||
struct selinfo *si = &priv->np_si[NR_TX]->si; | struct selinfo *si = &priv->np_si[NR_TX]->si; | ||||
D("remove selinfo %p", si); | D("remove selinfo %p", si); | ||||
knlist_remove(&si->si_note, kn, 0); | knlist_remove(&si->si_note, kn, /*islocked=*/0); | ||||
} | } | ||||
/* | /* | ||||
* callback from notifies (generated externally) and our | * Callback triggered by netmap notifications (see netmap_notify()), | ||||
* calls to kevent(). The former we just return 1 (ready) | * and by the application calling kevent(). In the former case we | ||||
* since we do not know better. | * just return 1 (events ready), since we are not able to do better. | ||||
* In the latter we call netmap_poll and return 0/1 accordingly. | * In the latter case we use netmap_poll() to see which events are | ||||
* ready. | |||||
*/ | */ | ||||
static int | static int | ||||
netmap_knrw(struct knote *kn, long hint, int events) | netmap_knrw(struct knote *kn, long hint, int events) | ||||
{ | { | ||||
struct netmap_priv_d *priv; | struct netmap_priv_d *priv; | ||||
int revents; | int revents; | ||||
if (hint != 0) { | if (hint != 0) { | ||||
ND(5, "call from notify"); | /* Called from netmap_notify(), typically from a | ||||
return 1; /* assume we are ready */ | * thread different from the one issuing kevent(). | ||||
* Assume we are ready. */ | |||||
return 1; | |||||
} | } | ||||
/* Called from kevent(). */ | |||||
priv = kn->kn_hook; | priv = kn->kn_hook; | ||||
/* the notification may come from an external thread, | revents = netmap_poll(priv, events, /*thread=*/NULL); | ||||
* in which case we do not want to run the netmap_poll | |||||
* This should be filtered above, but check just in case. | return (events & revents) ? 1 : 0; | ||||
*/ | |||||
if (curthread != priv->np_td) { /* should not happen */ | |||||
RD(5, "curthread changed %p %p", curthread, priv->np_td); | |||||
return 1; | |||||
} else { | |||||
revents = netmap_poll(priv, events, NULL); | |||||
return (events & revents) ? 1 : 0; | |||||
} | |||||
} | } | ||||
static int | static int | ||||
netmap_knread(struct knote *kn, long hint) | netmap_knread(struct knote *kn, long hint) | ||||
{ | { | ||||
return netmap_knrw(kn, hint, POLLIN); | return netmap_knrw(kn, hint, POLLIN); | ||||
} | } | ||||
Show All 14 Lines | |||||
.f_detach = netmap_knwdetach, | .f_detach = netmap_knwdetach, | ||||
.f_event = netmap_knwrite, | .f_event = netmap_knwrite, | ||||
}; | }; | ||||
/* | /* | ||||
* This is called when a thread invokes kevent() to record | * This is called when a thread invokes kevent() to record | ||||
* a change in the configuration of the kqueue(). | * a change in the configuration of the kqueue(). | ||||
* The 'priv' should be the same as in the netmap device. | * The 'priv' is the one associated to the open netmap device. | ||||
*/ | */ | ||||
static int | static int | ||||
netmap_kqfilter(struct cdev *dev, struct knote *kn) | netmap_kqfilter(struct cdev *dev, struct knote *kn) | ||||
{ | { | ||||
struct netmap_priv_d *priv; | struct netmap_priv_d *priv; | ||||
int error; | int error; | ||||
struct netmap_adapter *na; | struct netmap_adapter *na; | ||||
struct nm_selinfo *si; | struct nm_selinfo *si; | ||||
Show All 10 Lines | |||||
} | } | ||||
na = priv->np_na; | na = priv->np_na; | ||||
if (na == NULL) { | if (na == NULL) { | ||||
D("no netmap adapter for this file descriptor"); | D("no netmap adapter for this file descriptor"); | ||||
return 1; | return 1; | ||||
} | } | ||||
/* the si is indicated in the priv */ | /* the si is indicated in the priv */ | ||||
si = priv->np_si[(ev == EVFILT_WRITE) ? NR_TX : NR_RX]; | si = priv->np_si[(ev == EVFILT_WRITE) ? NR_TX : NR_RX]; | ||||
// XXX lock(priv) ? | |||||
kn->kn_fop = (ev == EVFILT_WRITE) ? | kn->kn_fop = (ev == EVFILT_WRITE) ? | ||||
&netmap_wfiltops : &netmap_rfiltops; | &netmap_wfiltops : &netmap_rfiltops; | ||||
kn->kn_hook = priv; | kn->kn_hook = priv; | ||||
knlist_add(&si->si.si_note, kn, 0); | knlist_add(&si->si.si_note, kn, /*islocked=*/0); | ||||
// XXX unlock(priv) | |||||
ND("register %p %s td %p priv %p kn %p np_nifp %p kn_fp/fpop %s", | |||||
na, na->ifp->if_xname, curthread, priv, kn, | |||||
priv->np_nifp, | |||||
kn->kn_fp == curthread->td_fpop ? "match" : "MISMATCH"); | |||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
freebsd_netmap_poll(struct cdev *cdevi __unused, int events, struct thread *td) | freebsd_netmap_poll(struct cdev *cdevi __unused, int events, struct thread *td) | ||||
{ | { | ||||
struct netmap_priv_d *priv; | struct netmap_priv_d *priv; | ||||
if (devfs_get_cdevpriv((void **)&priv)) { | if (devfs_get_cdevpriv((void **)&priv)) { | ||||
▲ Show 20 Lines • Show All 92 Lines • Show Last 20 Lines |
I think the comment should be updated.