svn commit: r274560 - in head/sys: kern sys
John-Mark Gurney
jmg at FreeBSD.org
Sun Nov 16 01:18:42 UTC 2014
Author: jmg
Date: Sun Nov 16 01:18:41 2014
New Revision: 274560
URL: https://svnweb.freebsd.org/changeset/base/274560
Log:
prevent doing filter ops locking for staticly compiled filter ops...
This significantly reduces lock contention when adding/removing knotes
on busy multi-kq system... Next step is to cache these references per
kq.. i.e. kq refs it once and keeps a local ref count so that the same
refs don't get accessed by many cpus...
only allocate a knote when we might use it...
Add a new flag, _FORCEONESHOT.. This allows a thread to force the
delivery of another event in a safe manner, say waking up an idle http
connection to force it to be reaped...
If we are _DISABLE'ing a knote, don't bother to call f_event on it, it's
disabled, so won't be delivered anyways..
Tested by: adrian
Modified:
head/sys/kern/kern_event.c
head/sys/sys/event.h
Modified: head/sys/kern/kern_event.c
==============================================================================
--- head/sys/kern/kern_event.c Sun Nov 16 01:00:39 2014 (r274559)
+++ head/sys/kern/kern_event.c Sun Nov 16 01:18:41 2014 (r274560)
@@ -281,19 +281,20 @@ MTX_SYSINIT(kqueue_filterops, &filterops
MTX_DEF);
static struct {
struct filterops *for_fop;
+ int for_nolock;
int for_refcnt;
} sysfilt_ops[EVFILT_SYSCOUNT] = {
- { &file_filtops }, /* EVFILT_READ */
- { &file_filtops }, /* EVFILT_WRITE */
+ { &file_filtops, 1 }, /* EVFILT_READ */
+ { &file_filtops, 1 }, /* EVFILT_WRITE */
{ &null_filtops }, /* EVFILT_AIO */
- { &file_filtops }, /* EVFILT_VNODE */
- { &proc_filtops }, /* EVFILT_PROC */
- { &sig_filtops }, /* EVFILT_SIGNAL */
- { &timer_filtops }, /* EVFILT_TIMER */
- { &file_filtops }, /* EVFILT_PROCDESC */
- { &fs_filtops }, /* EVFILT_FS */
+ { &file_filtops, 1 }, /* EVFILT_VNODE */
+ { &proc_filtops, 1 }, /* EVFILT_PROC */
+ { &sig_filtops, 1 }, /* EVFILT_SIGNAL */
+ { &timer_filtops, 1 }, /* EVFILT_TIMER */
+ { &file_filtops, 1 }, /* EVFILT_PROCDESC */
+ { &fs_filtops, 1 }, /* EVFILT_FS */
{ &null_filtops }, /* EVFILT_LIO */
- { &user_filtops }, /* EVFILT_USER */
+ { &user_filtops, 1 }, /* EVFILT_USER */
{ &null_filtops }, /* EVFILT_SENDFILE */
};
@@ -465,6 +466,10 @@ knote_fork(struct knlist *list, int pid)
list->kl_lock(list->kl_lockarg);
SLIST_FOREACH(kn, &list->kl_list, kn_selnext) {
+ /*
+ * XXX - Why do we skip the kn if it is _INFLUX? Does this
+ * mean we will not properly wake up some notes?
+ */
if ((kn->kn_status & KN_INFLUX) == KN_INFLUX)
continue;
kq = kn->kn_kq;
@@ -1002,6 +1007,9 @@ kqueue_fo_find(int filt)
if (filt > 0 || filt + EVFILT_SYSCOUNT < 0)
return NULL;
+ if (sysfilt_ops[~filt].for_nolock)
+ return sysfilt_ops[~filt].for_fop;
+
mtx_lock(&filterops_lock);
sysfilt_ops[~filt].for_refcnt++;
if (sysfilt_ops[~filt].for_fop == NULL)
@@ -1018,6 +1026,9 @@ kqueue_fo_release(int filt)
if (filt > 0 || filt + EVFILT_SYSCOUNT < 0)
return;
+ if (sysfilt_ops[~filt].for_nolock)
+ return;
+
mtx_lock(&filterops_lock);
KASSERT(sysfilt_ops[~filt].for_refcnt > 0,
("filter object refcount not valid on release"));
@@ -1051,7 +1062,10 @@ kqueue_register(struct kqueue *kq, struc
if (fops == NULL)
return EINVAL;
- tkn = knote_alloc(waitok); /* prevent waiting with locks */
+ if (kev->flags & EV_ADD)
+ tkn = knote_alloc(waitok); /* prevent waiting with locks */
+ else
+ tkn = NULL;
findkn:
if (fops->f_isfd) {
@@ -1162,7 +1176,7 @@ findkn:
kev->data = 0;
kn->kn_kevent = *kev;
kn->kn_kevent.flags &= ~(EV_ADD | EV_DELETE |
- EV_ENABLE | EV_DISABLE);
+ EV_ENABLE | EV_DISABLE | EV_FORCEONESHOT);
kn->kn_status = KN_INFLUX|KN_DETACHED;
error = knote_attach(kn, kq);
@@ -1195,6 +1209,11 @@ findkn:
goto done;
}
+ if (kev->flags & EV_FORCEONESHOT) {
+ kn->kn_flags |= EV_ONESHOT;
+ KNOTE_ACTIVATE(kn, 1);
+ }
+
/*
* The user may change some filter values after the initial EV_ADD,
* but doing so will not reset any filter which has already been
@@ -1219,18 +1238,21 @@ findkn:
* kn_knlist.
*/
done_ev_add:
- event = kn->kn_fop->f_event(kn, 0);
+ if ((kev->flags & EV_DISABLE) &&
+ ((kn->kn_status & KN_DISABLED) == 0)) {
+ kn->kn_status |= KN_DISABLED;
+ }
+
+ if ((kn->kn_status & KN_DISABLED) == 0)
+ event = kn->kn_fop->f_event(kn, 0);
+ else
+ event = 0;
KQ_LOCK(kq);
if (event)
KNOTE_ACTIVATE(kn, 1);
kn->kn_status &= ~(KN_INFLUX | KN_SCAN);
KN_LIST_UNLOCK(kn);
- if ((kev->flags & EV_DISABLE) &&
- ((kn->kn_status & KN_DISABLED) == 0)) {
- kn->kn_status |= KN_DISABLED;
- }
-
if ((kev->flags & EV_ENABLE) && (kn->kn_status & KN_DISABLED)) {
kn->kn_status &= ~KN_DISABLED;
if ((kn->kn_status & KN_ACTIVE) &&
Modified: head/sys/sys/event.h
==============================================================================
--- head/sys/sys/event.h Sun Nov 16 01:00:39 2014 (r274559)
+++ head/sys/sys/event.h Sun Nov 16 01:18:41 2014 (r274560)
@@ -69,6 +69,7 @@ struct kevent {
#define EV_DELETE 0x0002 /* delete event from kq */
#define EV_ENABLE 0x0004 /* enable event */
#define EV_DISABLE 0x0008 /* disable event (not reported) */
+#define EV_FORCEONESHOT 0x0100 /* enable _ONESHOT and force trigger */
/* flags */
#define EV_ONESHOT 0x0010 /* only report one occurrence */
More information about the svn-src-all
mailing list