Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Paste
P185
wait-free event handlers
Active
Public
Actions
Authored by
avg
on Jun 22 2018, 7:18 AM.
Edit Paste
Archive Paste
View Raw File
Subscribe
Mute Notifications
Flag For Later
Award Token
Tags
None
Referenced Files
F3466579: wait-free event handlers
Jun 22 2018, 7:18 AM
2018-06-22 07:18:41 (UTC+0)
Subscribers
None
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2018 Andriy Gapon <avg@freebsd.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _SYS_WFHANDLER_H_
#define _SYS_WFHANDLER_H_
#include
<sys/lock.h>
#include
<sys/mutex.h>
#include
<sys/queue.h>
typedef
void
wfhandler_cb
(
void
*
);
/* XXX */
struct
wfhandler_entry
{
SLIST_ENTRY
(
wfhandler_entry
)
wfe_link
;
wfhandler_cb
*
wfe_func
;
void
*
wfe_arg
;
int
wfe_priority
;
};
struct
wfhandler_list
{
struct
mtx
wfl_lock
;
SLIST_HEAD
(,
wfhandler_entry
)
wfl_entries
;
volatile
int
wfl_phase
;
volatile
int
wfl_active
[
2
];
};
/* Generic priority levels */
#define WFHANDLER_PRI_FIRST 0
#define WFHANDLER_PRI_ANY 10000
#define WFHANDLER_PRI_LAST 20000
void
wfhandler_list_init
(
const
char
*
name
,
struct
wfhandler_list
*
list
)
{
mtx_init
(
&
list
->
wfl_lock
,
name
,
NULL
,
MTX_DEF
);
SLIST_INIT
(
&
list
->
wfl_entries
);
list
->
wfl_phase
=
0
;
list
->
wfl_active
[
0
]
=
0
;
list
->
wfl_active
[
1
]
=
0
;
}
void
wfhandler_register
(
struct
wfhandler_list
*
list
,
struct
wfhandler_entry
*
entry
)
{
struct
wfhandler_entry
*
elm
;
struct
wfhandler_entry
**
prevptr
;
/* Serialize modifications. */
mtx_lock
(
&
list
->
wfl_lock
);
LIST_FOREACH_PREVPTR
(
elm
,
prevptr
,
&
list
->
wfl_entries
,
wfe_link
)
{
if
(
elm
->
wfe_priority
>
entry
->
wfe_priority
)
break
;
}
/*
* A replacement for SLIST_INSERT_AFTER that ensures that the new
* element is linked into the list after its next pointer has been
* setup. Also, the previous element is not required.
* prevptr, a pointer to the previous element's or the list head's
* pointer to the next element, is sufficient.
*/
SLIST_NEXT
(
entry
,
wfe_link
)
=
elm
;
atomic_store_rel_ptr
(
prevptr
,
entry
);
mtx_unlock
(
&
list
->
wfl_lock
);
}
void
wfhandler_deregister
(
struct
wfhandler_list
*
list
,
struct
wfhandler_entry
*
entry
)
{
struct
wfhandler_entry
*
elm
;
struct
wfhandler_entry
**
prevptr
;
int
phase
;
/* Serialize modifications. */
mtx_lock
(
&
list
->
wfl_lock
);
phase
=
list
->
wfl_phase
;
SLIST_FOREACH_PREVPTR
(
elm
,
prevptr
,
&
list
->
wfl_entries
,
wfe_link
)
{
if
(
elm
==
entry
)
{
/*
* Replacement for SLIST_REMOVE_AFTER and
* SLIST_REMOVE_HEAD that does not trash the next
* pointer in the removed element. It also can use
* prevptr instead of the previous element or the list
* head.
*/
*
prevptr
=
SLIST_NEXT
(
entry
,
wfe_link
);
break
;
}
}
KASSERT
(
elm
!=
NULL
,
(
"entry %p is not on handler list"
));
/* Switch new readers to the other busy counter. */
KASSERT
(
&
list
->
wfl_active
[
!
phase
]
==
0
,
(
"idle generation is busy"
));
atomic_store_rel_int
(
&
list
->
wfl_phase
,
!
phase
);
/*
* Make sure that the list and generation updates are not reordered
* with the check.
*/
atomic_thread_fence_seq_cst
();
/*
* Make sure that later operations are not reordered before the check.
*/
while
(
atomic_load_acq_int
(
&
list
->
wfl_active
[
gen
])
>
0
)
cpu_pause
();
mtx_unlock
(
&
list
->
wfl_lock
);
/* This code pokes into sys/queue.h internals. */
TRASHIT
(
entry
->
wfe_link
.
sle_next
);
}
void
wfhandler_invoke
(
struct
wfhandler_list
*
list
)
{
struct
wfhandler_entry
*
elm
;
int
phase
;
/*
* Ensure that all loads are after the busy count is updated
* for the current generation.
*/
phase
=
list
->
wfl_phase
;
atomic_add_acq_int
(
&
list
->
wfl_active
[
phase
],
1
);
SLIST_FOREACH
(
elm
,
&
list
->
wfl_entries
,
wfe_link
)
elm
->
wfe_func
(
elm
->
wfe_arg
);
/* Ensure that all loads are before the flag is reset. */
atomic_add_rel_int
(
&
list
->
wfl_active
[
phase
],
-1
);
}
#endif
/* _SYS_WFHANDLER_H_ */
Event Timeline
avg
created this paste.
Jun 22 2018, 7:18 AM
2018-06-22 07:18:41 (UTC+0)
avg
created this object in space
S1 Global
.
avg
created this object with edit policy "
avg (Andriy Gapon)
".
Log In to Comment