diff mbox

musl: add a sys/queue.h implementation

Message ID 1448924535-8093-1-git-send-email-sergio.prado@e-labworks.com
State Changes Requested
Headers show

Commit Message

Sergio Prado Nov. 30, 2015, 11:02 p.m. UTC
Musl does not provide a 'sys/queue.h' implementation, and this has been
a problem for packages that depend on it.

So lets create a package called sys-queue that will install 'sys/queue.h'
in the staging directory when enabled.

Musl toolchain and external toolchain packages will depend on this
package, so that 'sys/queue.h' will be always installed when compiling
with a musl based toolchain.

Tested on ARM and x86 in the following cases:
  - Buildroot musl toolchain.
  - External musl toolchain without 'sys/queue.h'.
  - External musl toolchain with 'sys/queue.h'.

Fixes:
http://autobuild.buildroot.net/results/24bad2d06ab40024dacf136bee722072d587f84e

And possibly many others.

Signed-off-by: Sergio Prado <sergio.prado@e-labworks.com>
---
 package/musl/musl.mk                               |   5 +
 package/sys-queue/Config.in                        |   8 +
 package/sys-queue/queue.h                          | 846 +++++++++++++++++++++
 package/sys-queue/sys-queue.mk                     |  23 +
 toolchain/toolchain-external/toolchain-external.mk |   7 +
 5 files changed, 889 insertions(+)
 create mode 100644 package/sys-queue/Config.in
 create mode 100644 package/sys-queue/queue.h
 create mode 100644 package/sys-queue/sys-queue.mk

Comments

Baruch Siach Dec. 1, 2015, 4:38 a.m. UTC | #1
Hi Sergio,

On Mon, Nov 30, 2015 at 09:02:15PM -0200, Sergio Prado wrote:
> Musl does not provide a 'sys/queue.h' implementation, and this has been
> a problem for packages that depend on it.
> 
> So lets create a package called sys-queue that will install 'sys/queue.h'
> in the staging directory when enabled.
> 
> Musl toolchain and external toolchain packages will depend on this
> package, so that 'sys/queue.h' will be always installed when compiling
> with a musl based toolchain.
> 
> Tested on ARM and x86 in the following cases:
>   - Buildroot musl toolchain.
>   - External musl toolchain without 'sys/queue.h'.
>   - External musl toolchain with 'sys/queue.h'.
> 
> Fixes:
> http://autobuild.buildroot.net/results/24bad2d06ab40024dacf136bee722072d587f84e
> 
> And possibly many others.
> 
> Signed-off-by: Sergio Prado <sergio.prado@e-labworks.com>

Thanks for working on this.

> +define SYS_QUEUE_INSTALL_STAGING_CMDS
> +	if [ ! -f $(STAGING_DIR)/usr/include/sys/queue.h ]; then \

We generally don't check for existence of files in target/staging, just 
overwrite them. Is there a reason to do this here? As I understand sys-queue 
is now a dependency of the toolchain, so if the toolchain provides sys/queue.h 
it will overwrite this one anyway.

> +		$(INSTALL) -D -m 0644 package/sys-queue/queue.h \
> +			$(STAGING_DIR)/usr/include/sys/queue.h; \
> +	fi
> +endef

baruch
Sergio Prado Dec. 1, 2015, 10:17 a.m. UTC | #2
Hi Baruch,

2015-12-01 2:38 GMT-02:00 Baruch Siach <baruch@tkos.co.il>:

> Hi Sergio,
>
> On Mon, Nov 30, 2015 at 09:02:15PM -0200, Sergio Prado wrote:
> > Musl does not provide a 'sys/queue.h' implementation, and this has been
> > a problem for packages that depend on it.
> >
> > So lets create a package called sys-queue that will install 'sys/queue.h'
> > in the staging directory when enabled.
> >
> > Musl toolchain and external toolchain packages will depend on this
> > package, so that 'sys/queue.h' will be always installed when compiling
> > with a musl based toolchain.
> >
> > Tested on ARM and x86 in the following cases:
> >   - Buildroot musl toolchain.
> >   - External musl toolchain without 'sys/queue.h'.
> >   - External musl toolchain with 'sys/queue.h'.
> >
> > Fixes:
> >
> http://autobuild.buildroot.net/results/24bad2d06ab40024dacf136bee722072d587f84e
> >
> > And possibly many others.
> >
> > Signed-off-by: Sergio Prado <sergio.prado@e-labworks.com>
>
> Thanks for working on this.
>
> > +define SYS_QUEUE_INSTALL_STAGING_CMDS
> > +     if [ ! -f $(STAGING_DIR)/usr/include/sys/queue.h ]; then \
>
> We generally don't check for existence of files in target/staging, just
> overwrite them. Is there a reason to do this here? As I understand
> sys-queue
> is now a dependency of the toolchain, so if the toolchain provides
> sys/queue.h
> it will overwrite this one anyway.
>

You are right. Initially, sys-queue would be installed after the external
toolchain package, so this would prevents from overriding the toolchain's
sys/queue.h implementation. But that's not the case anymore, so I'm OK with
removing this check.

Thanks!


>
> > +             $(INSTALL) -D -m 0644 package/sys-queue/queue.h \
> > +                     $(STAGING_DIR)/usr/include/sys/queue.h; \
> > +     fi
> > +endef
>
> baruch
>
> --
>      http://baruch.siach.name/blog/                  ~. .~   Tk Open
> Systems
> =}------------------------------------------------ooO--U--Ooo------------{=
>    - baruch@tkos.co.il - tel: +972.2.679.5364, http://www.tkos.co.il -
>
Thomas Petazzoni Dec. 1, 2015, 10:29 a.m. UTC | #3
Sergio,

On Mon, 30 Nov 2015 21:02:15 -0200, Sergio Prado wrote:

>  package/musl/musl.mk                               |   5 +
>  package/sys-queue/Config.in                        |   8 +
>  package/sys-queue/queue.h                          | 846 +++++++++++++++++++++

Rather than bundling the queue.h file, can we download it from some
location ? For example, you could use
http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/queue.h?rev=1.30.

> diff --git a/package/sys-queue/Config.in b/package/sys-queue/Config.in
> new file mode 100644
> index 000000000000..edc6610f6e65
> --- /dev/null
> +++ b/package/sys-queue/Config.in
> @@ -0,0 +1,8 @@
> +config BR2_PACKAGE_SYS_QUEUE
> +	bool "sys/queue.h support"
> +	help
> +	  Musl does not provide a 'sys/queue.h' implementation, and this would
> +	  be a problem for packages that depend on it.
> +
> +	  This package provides an implementation of 'sys/queue.h', based on 
> +	  the NetBSD implementation.

Do we really need this package to have a prompt? I think it could
remain a hidden package, no?

> diff --git a/package/sys-queue/sys-queue.mk b/package/sys-queue/sys-queue.mk
> new file mode 100644
> index 000000000000..053ef8fd9e0d
> --- /dev/null
> +++ b/package/sys-queue/sys-queue.mk
> @@ -0,0 +1,23 @@
> +################################################################################
> +#
> +# sys-queue
> +#
> +################################################################################
> +
> +# source included in buildroot
> +SYS_QUEUE_SOURCE =
> +SYS_QUEUE_VERSION = 1.70

Where is this version coming from ?

> +
> +SYS_QUEUE_LICENSE = BSD

BSD-3c

> +SYS_QUEUE_LICENSE_FILES = queue.h
> +
> +SYS_QUEUE_INSTALL_STAGING = YES
> +
> +define SYS_QUEUE_INSTALL_STAGING_CMDS
> +	if [ ! -f $(STAGING_DIR)/usr/include/sys/queue.h ]; then \
> +		$(INSTALL) -D -m 0644 package/sys-queue/queue.h \
> +			$(STAGING_DIR)/usr/include/sys/queue.h; \
> +	fi
> +endef

As Baruch said, please install unconditionally.

Otherwise, looks good to me.

Thanks!

Thomas
Sergio Prado Dec. 1, 2015, 10:44 a.m. UTC | #4
Hello Thomas,

2015-12-01 8:29 GMT-02:00 Thomas Petazzoni <
thomas.petazzoni@free-electrons.com>:

> Sergio,
>
> On Mon, 30 Nov 2015 21:02:15 -0200, Sergio Prado wrote:
>
> >  package/musl/musl.mk                               |   5 +
> >  package/sys-queue/Config.in                        |   8 +
> >  package/sys-queue/queue.h                          | 846
> +++++++++++++++++++++
>
> Rather than bundling the queue.h file, can we download it from some
> location ? For example, you could use
> http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/queue.h?rev=1.30.
>

One of my first questions was if we should keep queue.h inside Buildroot or
download it from somewhere. And you say we could keep it inside Buildroot,
and point me to package/makedevs/ that has a source code inside it. But I
can change it if that's a problem.


> > diff --git a/package/sys-queue/Config.in b/package/sys-queue/Config.in
> > new file mode 100644
> > index 000000000000..edc6610f6e65
> > --- /dev/null
> > +++ b/package/sys-queue/Config.in
> > @@ -0,0 +1,8 @@
> > +config BR2_PACKAGE_SYS_QUEUE
> > +     bool "sys/queue.h support"
> > +     help
> > +       Musl does not provide a 'sys/queue.h' implementation, and this
> would
> > +       be a problem for packages that depend on it.
> > +
> > +       This package provides an implementation of 'sys/queue.h', based
> on
> > +       the NetBSD implementation.
>
> Do we really need this package to have a prompt? I think it could
> remain a hidden package, no?
>

Since it is not included in the package/Config.in, it is still hidden,
right? At least I can't find it when searching inside menuconfig. I created
this file just as a matter of documentation, but I can remove if it is not
necessary.


>
> > diff --git a/package/sys-queue/sys-queue.mk b/package/sys-queue/
> sys-queue.mk
> > new file mode 100644
> > index 000000000000..053ef8fd9e0d
> > --- /dev/null
> > +++ b/package/sys-queue/sys-queue.mk
> > @@ -0,0 +1,23 @@
> >
> +################################################################################
> > +#
> > +# sys-queue
> > +#
> >
> +################################################################################
> > +
> > +# source included in buildroot
> > +SYS_QUEUE_SOURCE =
> > +SYS_QUEUE_VERSION = 1.70
>
> Where is this version coming from ?
>

From the source code.
http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/queue.h?rev=1.70


>
> > +
> > +SYS_QUEUE_LICENSE = BSD
>
> BSD-3c
>
> > +SYS_QUEUE_LICENSE_FILES = queue.h
> > +
> > +SYS_QUEUE_INSTALL_STAGING = YES
> > +
> > +define SYS_QUEUE_INSTALL_STAGING_CMDS
> > +     if [ ! -f $(STAGING_DIR)/usr/include/sys/queue.h ]; then \
> > +             $(INSTALL) -D -m 0644 package/sys-queue/queue.h \
> > +                     $(STAGING_DIR)/usr/include/sys/queue.h; \
> > +     fi
> > +endef
>
> As Baruch said, please install unconditionally.
>

OK.


>
> Otherwise, looks good to me.
>
> Thanks!
>

Thanks!


>
> Thomas
> --
> Thomas Petazzoni, CTO, Free Electrons
> Embedded Linux, Kernel and Android engineering
> http://free-electrons.com
>
Thomas Petazzoni Dec. 1, 2015, 11 a.m. UTC | #5
Sergio,

On Tue, 1 Dec 2015 08:44:59 -0200, Sergio Prado wrote:

> > Rather than bundling the queue.h file, can we download it from some
> > location ? For example, you could use
> > http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/queue.h?rev=1.30.
> 
> One of my first questions was if we should keep queue.h inside Buildroot or
> download it from somewhere. And you say we could keep it inside Buildroot,

Hum, are you sure your question was whether we should download it or
keep it inside Buildroot? I think your question was more "is it
possible to keep it inside Buildroot?", to which I answered yes,
indeed :-)

But anyway, doesn't really matter. I personally believe it's better to
download stuff when we can rather than bundling it. Hopefully others
will agree with me.


> > Do we really need this package to have a prompt? I think it could
> > remain a hidden package, no?
> 
> Since it is not included in the package/Config.in, it is still hidden,
> right? At least I can't find it when searching inside menuconfig. I created
> this file just as a matter of documentation, but I can remove if it is not
> necessary.

A Config.in that is not included anywhere is not useful at all, so it
shouldn't exist.

> > > +# source included in buildroot
> > > +SYS_QUEUE_SOURCE =
> > > +SYS_QUEUE_VERSION = 1.70
> >
> > Where is this version coming from ?
> 
> From the source code.
> http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/queue.h?rev=1.70

Alright, so it can be used in <pkg>_SOURCE. You will have to overwrite
the EXTRACT_CMDS however, because it's not a tarball. See jquery.mk for
example.

Thomas
Jörg Krause Dec. 1, 2015, 8:17 p.m. UTC | #6
Hi all,

On Mo, 2015-11-30 at 21:02 -0200, Sergio Prado wrote:
> Musl does not provide a 'sys/queue.h' implementation, and this has
> been
> a problem for packages that depend on it.
> 
> So lets create a package called sys-queue that will install
> 'sys/queue.h'
> in the staging directory when enabled.
> 
> Musl toolchain and external toolchain packages will depend on this
> package, so that 'sys/queue.h' will be always installed when
> compiling
> with a musl based toolchain.
> 

Maybe we can handle this similiar to the gettext integration and define
a BR2_NEEDS_SYS_QUEUE for toolchains not providing a queue library.

Packages that need a queue implementation can use 'select
BR2_PACKAGE_NETBSD_QUEUE if BR2_NEEDS_SYS_QUEUE' in their Config.in
file and add a '$(if $(BR2_NEEDS_SYS_QUEUE),netbsd-queue)' to their
dependencies in the .mk file. 

This means we have a package 'netbsd-queue' with the sources of the
NetBSD project you proposed. Note, there exists more implementations of
the queue library, e.g. OpenBSD, Apple, so I would prefer to use the
name of the implementation as there is no *the* sys/queue.h.

Furthermore, we allow a package to use, for whatever reasons, to select
a different queue implementation.

On the other hand, maybe it is to confusing for the package maintainer
to have different options for a queue library, so we just provide a
default package named 'sys-queue' using the sources of NetBSD?

Best regards
Jörg Krause
Arnout Vandecappelle Dec. 1, 2015, 8:34 p.m. UTC | #7
On 01-12-15 21:17, Jörg Krause wrote:
> Hi all,
> 
> On Mo, 2015-11-30 at 21:02 -0200, Sergio Prado wrote:
>> Musl does not provide a 'sys/queue.h' implementation, and this has
>> been
>> a problem for packages that depend on it.
>>
>> So lets create a package called sys-queue that will install
>> 'sys/queue.h'
>> in the staging directory when enabled.
>>
>> Musl toolchain and external toolchain packages will depend on this
>> package, so that 'sys/queue.h' will be always installed when
>> compiling
>> with a musl based toolchain.
>>
> 
> Maybe we can handle this similiar to the gettext integration and define
> a BR2_NEEDS_SYS_QUEUE for toolchains not providing a queue library.
> 
> Packages that need a queue implementation can use 'select
> BR2_PACKAGE_NETBSD_QUEUE if BR2_NEEDS_SYS_QUEUE' in their Config.in
> file and add a '$(if $(BR2_NEEDS_SYS_QUEUE),netbsd-queue)' to their
> dependencies in the .mk file. 

 This would add quite a lot of complexity. Unconditionally installing
sys/queue.h for musl libraries is really a lot simpler.

> 
> This means we have a package 'netbsd-queue' with the sources of the
> NetBSD project you proposed. Note, there exists more implementations of
> the queue library, e.g. OpenBSD, Apple, so I would prefer to use the
> name of the implementation as there is no *the* sys/queue.h.

 That's a good idea. Not that I expect we'll ever carry another queue
implementation (actually we already have two: uClibc and glibc).

 Regards,
 Arnout

> 
> Furthermore, we allow a package to use, for whatever reasons, to select
> a different queue implementation.
> 
> On the other hand, maybe it is to confusing for the package maintainer
> to have different options for a queue library, so we just provide a
> default package named 'sys-queue' using the sources of NetBSD?
> 
> Best regards
> Jörg Krause
> _______________________________________________
> buildroot mailing list
> buildroot@busybox.net
> http://lists.busybox.net/mailman/listinfo/buildroot
>
Sergio Prado Dec. 1, 2015, 9:14 p.m. UTC | #8
2015-12-01 9:00 GMT-02:00 Thomas Petazzoni <
thomas.petazzoni@free-electrons.com>:

> Sergio,
>
> On Tue, 1 Dec 2015 08:44:59 -0200, Sergio Prado wrote:
>
> > > Rather than bundling the queue.h file, can we download it from some
> > > location ? For example, you could use
> > > http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/queue.h?rev=1.30.
> >
> > One of my first questions was if we should keep queue.h inside Buildroot
> or
> > download it from somewhere. And you say we could keep it inside
> Buildroot,
>
> Hum, are you sure your question was whether we should download it or
> keep it inside Buildroot? I think your question was more "is it
> possible to keep it inside Buildroot?", to which I answered yes,
> indeed :-)
>
> But anyway, doesn't really matter. I personally believe it's better to
> download stuff when we can rather than bundling it. Hopefully others
> will agree with me.
>

OK. I'll do it.


>
>
> > > Do we really need this package to have a prompt? I think it could
> > > remain a hidden package, no?
> >
> > Since it is not included in the package/Config.in, it is still hidden,
> > right? At least I can't find it when searching inside menuconfig. I
> created
> > this file just as a matter of documentation, but I can remove if it is
> not
> > necessary.
>
> A Config.in that is not included anywhere is not useful at all, so it
> shouldn't exist.
>

Right.


>
> > > > +# source included in buildroot
> > > > +SYS_QUEUE_SOURCE =
> > > > +SYS_QUEUE_VERSION = 1.70
> > >
> > > Where is this version coming from ?
> >
> > From the source code.
> > http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/queue.h?rev=1.70
>
> Alright, so it can be used in <pkg>_SOURCE. You will have to overwrite
> the EXTRACT_CMDS however, because it's not a tarball. See jquery.mk for
> example.
>

OK, thanks.


>
> Thomas
> --
> Thomas Petazzoni, CTO, Free Electrons
> Embedded Linux, Kernel and Android engineering
> http://free-electrons.com
>
Sergio Prado Dec. 1, 2015, 9:15 p.m. UTC | #9
2015-12-01 18:34 GMT-02:00 Arnout Vandecappelle <arnout@mind.be>:

> On 01-12-15 21:17, Jörg Krause wrote:
> > Hi all,
> >
> > On Mo, 2015-11-30 at 21:02 -0200, Sergio Prado wrote:
> >> Musl does not provide a 'sys/queue.h' implementation, and this has
> >> been
> >> a problem for packages that depend on it.
> >>
> >> So lets create a package called sys-queue that will install
> >> 'sys/queue.h'
> >> in the staging directory when enabled.
> >>
> >> Musl toolchain and external toolchain packages will depend on this
> >> package, so that 'sys/queue.h' will be always installed when
> >> compiling
> >> with a musl based toolchain.
> >>
> >
> > Maybe we can handle this similiar to the gettext integration and define
> > a BR2_NEEDS_SYS_QUEUE for toolchains not providing a queue library.
> >
> > Packages that need a queue implementation can use 'select
> > BR2_PACKAGE_NETBSD_QUEUE if BR2_NEEDS_SYS_QUEUE' in their Config.in
> > file and add a '$(if $(BR2_NEEDS_SYS_QUEUE),netbsd-queue)' to their
> > dependencies in the .mk file.
>
>  This would add quite a lot of complexity. Unconditionally installing
> sys/queue.h for musl libraries is really a lot simpler.
>
> >
> > This means we have a package 'netbsd-queue' with the sources of the
> > NetBSD project you proposed. Note, there exists more implementations of
> > the queue library, e.g. OpenBSD, Apple, so I would prefer to use the
> > name of the implementation as there is no *the* sys/queue.h.
>
>  That's a good idea. Not that I expect we'll ever carry another queue
> implementation (actually we already have two: uClibc and glibc).
>

I liked the idea. I'll rename the package to netbsd-queue.


>  Regards,
>  Arnout
>
> >
> > Furthermore, we allow a package to use, for whatever reasons, to select
> > a different queue implementation.
> >
> > On the other hand, maybe it is to confusing for the package maintainer
> > to have different options for a queue library, so we just provide a
> > default package named 'sys-queue' using the sources of NetBSD?
> >
> > Best regards
> > Jörg Krause
> > _______________________________________________
> > buildroot mailing list
> > buildroot@busybox.net
> > http://lists.busybox.net/mailman/listinfo/buildroot
> >
>
>
> --
> Arnout Vandecappelle                          arnout at mind be
> Senior Embedded Software Architect            +32-16-286500
> Essensium/Mind                                http://www.mind.be
> G.Geenslaan 9, 3001 Leuven, Belgium           BE 872 984 063 RPR Leuven
> LinkedIn profile: http://www.linkedin.com/in/arnoutvandecappelle
> GPG fingerprint:  7493 020B C7E3 8618 8DEC 222C 82EB F404 F9AC 0DDF
>
diff mbox

Patch

diff --git a/package/musl/musl.mk b/package/musl/musl.mk
index 6fdcc7312288..45843e4893c6 100644
--- a/package/musl/musl.mk
+++ b/package/musl/musl.mk
@@ -13,6 +13,11 @@  MUSL_LICENSE_FILES = COPYRIGHT
 # cross-compiler and the kernel headers
 MUSL_DEPENDENCIES = host-gcc-initial linux-headers
 
+# musl does not provide a sys/queue.h implementation, so add the
+# sys-queue package that will install a sys/queue.h file in the
+# staging directory based on the NetBSD implementation.
+MUSL_DEPENDENCIES += sys-queue
+
 # musl is part of the toolchain so disable the toolchain dependency
 MUSL_ADD_TOOLCHAIN_DEPENDENCY = NO
 
diff --git a/package/sys-queue/Config.in b/package/sys-queue/Config.in
new file mode 100644
index 000000000000..edc6610f6e65
--- /dev/null
+++ b/package/sys-queue/Config.in
@@ -0,0 +1,8 @@ 
+config BR2_PACKAGE_SYS_QUEUE
+	bool "sys/queue.h support"
+	help
+	  Musl does not provide a 'sys/queue.h' implementation, and this would
+	  be a problem for packages that depend on it.
+
+	  This package provides an implementation of 'sys/queue.h', based on 
+	  the NetBSD implementation.
diff --git a/package/sys-queue/queue.h b/package/sys-queue/queue.h
new file mode 100644
index 000000000000..a38499a2673d
--- /dev/null
+++ b/package/sys-queue/queue.h
@@ -0,0 +1,846 @@ 
+/*	$NetBSD: queue.h,v 1.70 2015/11/02 15:21:23 christos Exp $	*/
+
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef	_SYS_QUEUE_H_
+#define	_SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The
+ * elements are singly linked for minimum space and pointer manipulation
+ * overhead at the expense of O(n) removal for arbitrary elements. New
+ * elements can be added to the list after an existing element or at the
+ * head of the list.  Elements being removed from the head of the list
+ * should use the explicit macro for this purpose for optimum
+ * efficiency. A singly-linked list may only be traversed in the forward
+ * direction.  Singly-linked lists are ideal for applications with large
+ * datasets and few or no removals or for implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * Include the definition of NULL only on NetBSD because sys/null.h
+ * is not available elsewhere.  This conditional makes the header
+ * portable and it can simply be dropped verbatim into any system.
+ * The caveat is that on other systems some other header
+ * must provide NULL before the macros can be used.
+ */
+#ifdef __NetBSD__
+#include <sys/null.h>
+#endif
+
+#if defined(QUEUEDEBUG)
+# if defined(_KERNEL)
+#  define QUEUEDEBUG_ABORT(...) panic(__VA_ARGS__)
+# else
+#  include <err.h>
+#  define QUEUEDEBUG_ABORT(...) err(1, __VA_ARGS__)
+# endif
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define	SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define	SLIST_FIRST(head)	((head)->slh_first)
+#define	SLIST_END(head)		NULL
+#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for((var) = (head)->slh_first;					\
+	    (var) != SLIST_END(head);					\
+	    (var) = (var)->field.sle_next)
+
+#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var) != SLIST_END(head) &&					\
+	    ((tvar) = SLIST_NEXT((var), field), 1);			\
+	    (var) = (tvar))
+
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_INIT(head) do {						\
+	(head)->slh_first = SLIST_END(head);				\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	(elm)->field.sle_next = (slistelm)->field.sle_next;		\
+	(slistelm)->field.sle_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	(elm)->field.sle_next = (head)->slh_first;			\
+	(head)->slh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_REMOVE_AFTER(slistelm, field) do {			\
+	(slistelm)->field.sle_next =					\
+	    SLIST_NEXT(SLIST_NEXT((slistelm), field), field);		\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	(head)->slh_first = (head)->slh_first->field.sle_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_REMOVE(head, elm, type, field) do {			\
+	if ((head)->slh_first == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = (head)->slh_first;		\
+		while(curelm->field.sle_next != (elm))			\
+			curelm = curelm->field.sle_next;		\
+		curelm->field.sle_next =				\
+		    curelm->field.sle_next->field.sle_next;		\
+	}								\
+} while (/*CONSTCOND*/0)
+
+
+/*
+ * List definitions.
+ */
+#define	LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define	LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List access methods.
+ */
+#define	LIST_FIRST(head)		((head)->lh_first)
+#define	LIST_END(head)			NULL
+#define	LIST_EMPTY(head)		((head)->lh_first == LIST_END(head))
+#define	LIST_NEXT(elm, field)		((elm)->field.le_next)
+
+#define	LIST_FOREACH(var, head, field)					\
+	for ((var) = ((head)->lh_first);				\
+	    (var) != LIST_END(head);					\
+	    (var) = ((var)->field.le_next))
+
+#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = LIST_FIRST((head));				\
+	    (var) != LIST_END(head) &&					\
+	    ((tvar) = LIST_NEXT((var), field), 1);			\
+	    (var) = (tvar))
+
+#define	LIST_MOVE(head1, head2) do {					\
+	LIST_INIT((head2));						\
+	if (!LIST_EMPTY((head1))) {					\
+		(head2)->lh_first = (head1)->lh_first;			\
+		LIST_INIT((head1));					\
+	}								\
+} while (/*CONSTCOND*/0)
+
+/*
+ * List functions.
+ */
+#if defined(QUEUEDEBUG)
+#define	QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field)			\
+	if ((head)->lh_first &&						\
+	    (head)->lh_first->field.le_prev != &(head)->lh_first)	\
+		QUEUEDEBUG_ABORT("LIST_INSERT_HEAD %p %s:%d", (head),	\
+		    __FILE__, __LINE__);
+#define	QUEUEDEBUG_LIST_OP(elm, field)					\
+	if ((elm)->field.le_next &&					\
+	    (elm)->field.le_next->field.le_prev !=			\
+	    &(elm)->field.le_next)					\
+		QUEUEDEBUG_ABORT("LIST_* forw %p %s:%d", (elm),		\
+		    __FILE__, __LINE__);				\
+	if (*(elm)->field.le_prev != (elm))				\
+		QUEUEDEBUG_ABORT("LIST_* back %p %s:%d", (elm),		\
+		    __FILE__, __LINE__);
+#define	QUEUEDEBUG_LIST_POSTREMOVE(elm, field)				\
+	(elm)->field.le_next = (void *)1L;				\
+	(elm)->field.le_prev = (void *)1L;
+#else
+#define	QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field)
+#define	QUEUEDEBUG_LIST_OP(elm, field)
+#define	QUEUEDEBUG_LIST_POSTREMOVE(elm, field)
+#endif
+
+#define	LIST_INIT(head) do {						\
+	(head)->lh_first = LIST_END(head);				\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	QUEUEDEBUG_LIST_OP((listelm), field)				\
+	if (((elm)->field.le_next = (listelm)->field.le_next) != 	\
+	    LIST_END(head))						\
+		(listelm)->field.le_next->field.le_prev =		\
+		    &(elm)->field.le_next;				\
+	(listelm)->field.le_next = (elm);				\
+	(elm)->field.le_prev = &(listelm)->field.le_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	QUEUEDEBUG_LIST_OP((listelm), field)				\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	(elm)->field.le_next = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &(elm)->field.le_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_INSERT_HEAD(head, elm, field) do {				\
+	QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field)		\
+	if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\
+		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+	(head)->lh_first = (elm);					\
+	(elm)->field.le_prev = &(head)->lh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_REMOVE(elm, field) do {					\
+	QUEUEDEBUG_LIST_OP((elm), field)				\
+	if ((elm)->field.le_next != NULL)				\
+		(elm)->field.le_next->field.le_prev = 			\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = (elm)->field.le_next;			\
+	QUEUEDEBUG_LIST_POSTREMOVE((elm), field)			\
+} while (/*CONSTCOND*/0)
+
+#define LIST_REPLACE(elm, elm2, field) do {				\
+	if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)	\
+		(elm2)->field.le_next->field.le_prev =			\
+		    &(elm2)->field.le_next;				\
+	(elm2)->field.le_prev = (elm)->field.le_prev;			\
+	*(elm2)->field.le_prev = (elm2);				\
+	QUEUEDEBUG_LIST_POSTREMOVE((elm), field)			\
+} while (/*CONSTCOND*/0)
+
+/*
+ * Simple queue definitions.
+ */
+#define	SIMPLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *sqh_first;	/* first element */			\
+	struct type **sqh_last;	/* addr of last next element */		\
+}
+
+#define	SIMPLEQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).sqh_first }
+
+#define	SIMPLEQ_ENTRY(type)						\
+struct {								\
+	struct type *sqe_next;	/* next element */			\
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define	SIMPLEQ_FIRST(head)		((head)->sqh_first)
+#define	SIMPLEQ_END(head)		NULL
+#define	SIMPLEQ_EMPTY(head)		((head)->sqh_first == SIMPLEQ_END(head))
+#define	SIMPLEQ_NEXT(elm, field)	((elm)->field.sqe_next)
+
+#define	SIMPLEQ_FOREACH(var, head, field)				\
+	for ((var) = ((head)->sqh_first);				\
+	    (var) != SIMPLEQ_END(head);					\
+	    (var) = ((var)->field.sqe_next))
+
+#define	SIMPLEQ_FOREACH_SAFE(var, head, field, next)			\
+	for ((var) = ((head)->sqh_first);				\
+	    (var) != SIMPLEQ_END(head) &&				\
+	    ((next = ((var)->field.sqe_next)), 1);			\
+	    (var) = (next))
+
+/*
+ * Simple queue functions.
+ */
+#define	SIMPLEQ_INIT(head) do {						\
+	(head)->sqh_first = NULL;					\
+	(head)->sqh_last = &(head)->sqh_first;				\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(head)->sqh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.sqe_next = NULL;					\
+	*(head)->sqh_last = (elm);					\
+	(head)->sqh_last = &(elm)->field.sqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(listelm)->field.sqe_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_REMOVE_HEAD(head, field) do {				\
+	if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+		(head)->sqh_last = &(head)->sqh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
+	if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
+	    == NULL)							\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_REMOVE(head, elm, type, field) do {			\
+	if ((head)->sqh_first == (elm)) {				\
+		SIMPLEQ_REMOVE_HEAD((head), field);			\
+	} else {							\
+		struct type *curelm = (head)->sqh_first;		\
+		while (curelm->field.sqe_next != (elm))			\
+			curelm = curelm->field.sqe_next;		\
+		if ((curelm->field.sqe_next =				\
+			curelm->field.sqe_next->field.sqe_next) == NULL) \
+			    (head)->sqh_last = &(curelm)->field.sqe_next; \
+	}								\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_CONCAT(head1, head2) do {				\
+	if (!SIMPLEQ_EMPTY((head2))) {					\
+		*(head1)->sqh_last = (head2)->sqh_first;		\
+		(head1)->sqh_last = (head2)->sqh_last;		\
+		SIMPLEQ_INIT((head2));					\
+	}								\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_LAST(head, type, field)					\
+	(SIMPLEQ_EMPTY((head)) ?						\
+		NULL :							\
+	        ((struct type *)(void *)				\
+		((char *)((head)->sqh_last) - offsetof(struct type, field))))
+
+/*
+ * Tail queue definitions.
+ */
+#define	_TAILQ_HEAD(name, type, qual)					\
+struct name {								\
+	qual type *tqh_first;		/* first element */		\
+	qual type *qual *tqh_last;	/* addr of last next element */	\
+}
+#define TAILQ_HEAD(name, type)	_TAILQ_HEAD(name, struct type,)
+
+#define	TAILQ_HEAD_INITIALIZER(head)					\
+	{ TAILQ_END(head), &(head).tqh_first }
+
+#define	_TAILQ_ENTRY(type, qual)					\
+struct {								\
+	qual type *tqe_next;		/* next element */		\
+	qual type *qual *tqe_prev;	/* address of previous next element */\
+}
+#define TAILQ_ENTRY(type)	_TAILQ_ENTRY(struct type,)
+
+/*
+ * Tail queue access methods.
+ */
+#define	TAILQ_FIRST(head)		((head)->tqh_first)
+#define	TAILQ_END(head)			(NULL)
+#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
+#define	TAILQ_LAST(head, headname) \
+	(*(((struct headname *)(void *)((head)->tqh_last))->tqh_last))
+#define	TAILQ_PREV(elm, headname, field) \
+	(*(((struct headname *)(void *)((elm)->field.tqe_prev))->tqh_last))
+#define	TAILQ_EMPTY(head)		(TAILQ_FIRST(head) == TAILQ_END(head))
+
+
+#define	TAILQ_FOREACH(var, head, field)					\
+	for ((var) = ((head)->tqh_first);				\
+	    (var) != TAILQ_END(head);					\
+	    (var) = ((var)->field.tqe_next))
+
+#define	TAILQ_FOREACH_SAFE(var, head, field, next)			\
+	for ((var) = ((head)->tqh_first);				\
+	    (var) != TAILQ_END(head) &&					\
+	    ((next) = TAILQ_NEXT(var, field), 1); (var) = (next))
+
+#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var) != TAILQ_END(head);					\
+	    (var) = TAILQ_PREV((var), headname, field))
+
+#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev)	\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var) != TAILQ_END(head) && 				\
+	    ((prev) = TAILQ_PREV((var), headname, field), 1); (var) = (prev))
+
+/*
+ * Tail queue functions.
+ */
+#if defined(QUEUEDEBUG)
+#define	QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field)			\
+	if ((head)->tqh_first &&					\
+	    (head)->tqh_first->field.tqe_prev != &(head)->tqh_first)	\
+		QUEUEDEBUG_ABORT("TAILQ_INSERT_HEAD %p %s:%d", (head),	\
+		    __FILE__, __LINE__);
+#define	QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field)			\
+	if (*(head)->tqh_last != NULL)					\
+		QUEUEDEBUG_ABORT("TAILQ_INSERT_TAIL %p %s:%d", (head),	\
+		    __FILE__, __LINE__);
+#define	QUEUEDEBUG_TAILQ_OP(elm, field)					\
+	if ((elm)->field.tqe_next &&					\
+	    (elm)->field.tqe_next->field.tqe_prev !=			\
+	    &(elm)->field.tqe_next)					\
+		QUEUEDEBUG_ABORT("TAILQ_* forw %p %s:%d", (elm),	\
+		    __FILE__, __LINE__);				\
+	if (*(elm)->field.tqe_prev != (elm))				\
+		QUEUEDEBUG_ABORT("TAILQ_* back %p %s:%d", (elm),	\
+		    __FILE__, __LINE__);
+#define	QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field)			\
+	if ((elm)->field.tqe_next == NULL &&				\
+	    (head)->tqh_last != &(elm)->field.tqe_next)			\
+		QUEUEDEBUG_ABORT("TAILQ_PREREMOVE head %p elm %p %s:%d",\
+		    (head), (elm), __FILE__, __LINE__);
+#define	QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field)				\
+	(elm)->field.tqe_next = (void *)1L;				\
+	(elm)->field.tqe_prev = (void *)1L;
+#else
+#define	QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field)
+#define	QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field)
+#define	QUEUEDEBUG_TAILQ_OP(elm, field)
+#define	QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field)
+#define	QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field)
+#endif
+
+#define	TAILQ_INIT(head) do {						\
+	(head)->tqh_first = TAILQ_END(head);				\
+	(head)->tqh_last = &(head)->tqh_first;				\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field)		\
+	if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\
+		(head)->tqh_first->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(head)->tqh_first = (elm);					\
+	(elm)->field.tqe_prev = &(head)->tqh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field)		\
+	(elm)->field.tqe_next = TAILQ_END(head);			\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &(elm)->field.tqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	QUEUEDEBUG_TAILQ_OP((listelm), field)				\
+	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != 	\
+	    TAILQ_END(head))						\
+		(elm)->field.tqe_next->field.tqe_prev = 		\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(listelm)->field.tqe_next = (elm);				\
+	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	QUEUEDEBUG_TAILQ_OP((listelm), field)				\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	(elm)->field.tqe_next = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_REMOVE(head, elm, field) do {				\
+	QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field)		\
+	QUEUEDEBUG_TAILQ_OP((elm), field)				\
+	if (((elm)->field.tqe_next) != TAILQ_END(head))			\
+		(elm)->field.tqe_next->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
+	QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field);			\
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do {			\
+        if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != 	\
+	    TAILQ_END(head))   						\
+                (elm2)->field.tqe_next->field.tqe_prev =		\
+                    &(elm2)->field.tqe_next;				\
+        else								\
+                (head)->tqh_last = &(elm2)->field.tqe_next;		\
+        (elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
+        *(elm2)->field.tqe_prev = (elm2);				\
+	QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field);			\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_CONCAT(head1, head2, field) do {				\
+	if (!TAILQ_EMPTY(head2)) {					\
+		*(head1)->tqh_last = (head2)->tqh_first;		\
+		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\
+		(head1)->tqh_last = (head2)->tqh_last;			\
+		TAILQ_INIT((head2));					\
+	}								\
+} while (/*CONSTCOND*/0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define	STAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *stqh_first;	/* first element */		\
+	struct type **stqh_last;	/* addr of last next element */	\
+}
+
+#define	STAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).stqh_first }
+
+#define	STAILQ_ENTRY(type)						\
+struct {								\
+	struct type *stqe_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked Tail queue access methods.
+ */
+#define	STAILQ_FIRST(head)	((head)->stqh_first)
+#define	STAILQ_END(head)	NULL
+#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
+#define	STAILQ_EMPTY(head)	(STAILQ_FIRST(head) == STAILQ_END(head))
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define	STAILQ_INIT(head) do {						\
+	(head)->stqh_first = NULL;					\
+	(head)->stqh_last = &(head)->stqh_first;				\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.stqe_next = (head)->stqh_first) == NULL)	\
+		(head)->stqh_last = &(elm)->field.stqe_next;		\
+	(head)->stqh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.stqe_next = NULL;					\
+	*(head)->stqh_last = (elm);					\
+	(head)->stqh_last = &(elm)->field.stqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
+		(head)->stqh_last = &(elm)->field.stqe_next;		\
+	(listelm)->field.stqe_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_REMOVE_HEAD(head, field) do {				\
+	if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
+		(head)->stqh_last = &(head)->stqh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	if ((head)->stqh_first == (elm)) {				\
+		STAILQ_REMOVE_HEAD((head), field);			\
+	} else {							\
+		struct type *curelm = (head)->stqh_first;		\
+		while (curelm->field.stqe_next != (elm))			\
+			curelm = curelm->field.stqe_next;		\
+		if ((curelm->field.stqe_next =				\
+			curelm->field.stqe_next->field.stqe_next) == NULL) \
+			    (head)->stqh_last = &(curelm)->field.stqe_next; \
+	}								\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_FOREACH(var, head, field)				\
+	for ((var) = ((head)->stqh_first);				\
+		(var);							\
+		(var) = ((var)->field.stqe_next))
+
+#define	STAILQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = STAILQ_FIRST((head));				\
+	    (var) && ((tvar) = STAILQ_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	STAILQ_CONCAT(head1, head2) do {				\
+	if (!STAILQ_EMPTY((head2))) {					\
+		*(head1)->stqh_last = (head2)->stqh_first;		\
+		(head1)->stqh_last = (head2)->stqh_last;		\
+		STAILQ_INIT((head2));					\
+	}								\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_LAST(head, type, field)					\
+	(STAILQ_EMPTY((head)) ?						\
+		NULL :							\
+	        ((struct type *)(void *)				\
+		((char *)((head)->stqh_last) - offsetof(struct type, field))))
+
+
+#ifndef _KERNEL
+/*
+ * Circular queue definitions. Do not use. We still keep the macros
+ * for compatibility but because of pointer aliasing issues their use
+ * is discouraged!
+ */
+
+/*
+ * __launder_type():  We use this ugly hack to work around the the compiler
+ * noticing that two types may not alias each other and elide tests in code.
+ * We hit this in the CIRCLEQ macros when comparing 'struct name *' and
+ * 'struct type *' (see CIRCLEQ_HEAD()).  Modern compilers (such as GCC
+ * 4.8) declare these comparisons as always false, causing the code to
+ * not run as designed.
+ *
+ * This hack is only to be used for comparisons and thus can be fully const.
+ * Do not use for assignment.
+ *
+ * If we ever choose to change the ABI of the CIRCLEQ macros, we could fix
+ * this by changing the head/tail sentinal values, but see the note above
+ * this one.
+ */
+static __inline const void * __launder_type(const void *);
+static __inline const void *
+__launder_type(const void *__x)
+{
+	__asm __volatile("" : "+r" (__x));
+	return __x;
+}
+
+#if defined(QUEUEDEBUG)
+#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field)				\
+	if ((head)->cqh_first != CIRCLEQ_ENDC(head) &&			\
+	    (head)->cqh_first->field.cqe_prev != CIRCLEQ_ENDC(head))	\
+		QUEUEDEBUG_ABORT("CIRCLEQ head forw %p %s:%d", (head),	\
+		      __FILE__, __LINE__);				\
+	if ((head)->cqh_last != CIRCLEQ_ENDC(head) &&			\
+	    (head)->cqh_last->field.cqe_next != CIRCLEQ_ENDC(head))	\
+		QUEUEDEBUG_ABORT("CIRCLEQ head back %p %s:%d", (head),	\
+		      __FILE__, __LINE__);
+#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field)			\
+	if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) {		\
+		if ((head)->cqh_last != (elm))				\
+			QUEUEDEBUG_ABORT("CIRCLEQ elm last %p %s:%d",	\
+			    (elm), __FILE__, __LINE__);			\
+	} else {							\
+		if ((elm)->field.cqe_next->field.cqe_prev != (elm))	\
+			QUEUEDEBUG_ABORT("CIRCLEQ elm forw %p %s:%d",	\
+			    (elm), __FILE__, __LINE__);			\
+	}								\
+	if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) {		\
+		if ((head)->cqh_first != (elm))				\
+			QUEUEDEBUG_ABORT("CIRCLEQ elm first %p %s:%d",	\
+			    (elm), __FILE__, __LINE__);			\
+	} else {							\
+		if ((elm)->field.cqe_prev->field.cqe_next != (elm))	\
+			QUEUEDEBUG_ABORT("CIRCLEQ elm prev %p %s:%d",	\
+			    (elm), __FILE__, __LINE__);			\
+	}
+#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field)			\
+	(elm)->field.cqe_next = (void *)1L;				\
+	(elm)->field.cqe_prev = (void *)1L;
+#else
+#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field)
+#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field)
+#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field)
+#endif
+
+#define	CIRCLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *cqh_first;		/* first element */		\
+	struct type *cqh_last;		/* last element */		\
+}
+
+#define	CIRCLEQ_HEAD_INITIALIZER(head)					\
+	{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define	CIRCLEQ_ENTRY(type)						\
+struct {								\
+	struct type *cqe_next;		/* next element */		\
+	struct type *cqe_prev;		/* previous element */		\
+}
+
+/*
+ * Circular queue functions.
+ */
+#define	CIRCLEQ_INIT(head) do {						\
+	(head)->cqh_first = CIRCLEQ_END(head);				\
+	(head)->cqh_last = CIRCLEQ_END(head);				\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	QUEUEDEBUG_CIRCLEQ_HEAD((head), field)				\
+	QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field)		\
+	(elm)->field.cqe_next = (listelm)->field.cqe_next;		\
+	(elm)->field.cqe_prev = (listelm);				\
+	if ((listelm)->field.cqe_next == CIRCLEQ_ENDC(head))		\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(listelm)->field.cqe_next->field.cqe_prev = (elm);	\
+	(listelm)->field.cqe_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {		\
+	QUEUEDEBUG_CIRCLEQ_HEAD((head), field)				\
+	QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field)		\
+	(elm)->field.cqe_next = (listelm);				\
+	(elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
+	if ((listelm)->field.cqe_prev == CIRCLEQ_ENDC(head))		\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(listelm)->field.cqe_prev->field.cqe_next = (elm);	\
+	(listelm)->field.cqe_prev = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
+	QUEUEDEBUG_CIRCLEQ_HEAD((head), field)				\
+	(elm)->field.cqe_next = (head)->cqh_first;			\
+	(elm)->field.cqe_prev = CIRCLEQ_END(head);			\
+	if ((head)->cqh_last == CIRCLEQ_ENDC(head))			\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(head)->cqh_first->field.cqe_prev = (elm);		\
+	(head)->cqh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
+	QUEUEDEBUG_CIRCLEQ_HEAD((head), field)				\
+	(elm)->field.cqe_next = CIRCLEQ_END(head);			\
+	(elm)->field.cqe_prev = (head)->cqh_last;			\
+	if ((head)->cqh_first == CIRCLEQ_ENDC(head))			\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(head)->cqh_last->field.cqe_next = (elm);		\
+	(head)->cqh_last = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_REMOVE(head, elm, field) do {				\
+	QUEUEDEBUG_CIRCLEQ_HEAD((head), field)				\
+	QUEUEDEBUG_CIRCLEQ_ELM((head), (elm), field)			\
+	if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head))		\
+		(head)->cqh_last = (elm)->field.cqe_prev;		\
+	else								\
+		(elm)->field.cqe_next->field.cqe_prev =			\
+		    (elm)->field.cqe_prev;				\
+	if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head))		\
+		(head)->cqh_first = (elm)->field.cqe_next;		\
+	else								\
+		(elm)->field.cqe_prev->field.cqe_next =			\
+		    (elm)->field.cqe_next;				\
+	QUEUEDEBUG_CIRCLEQ_POSTREMOVE((elm), field)			\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_FOREACH(var, head, field)				\
+	for ((var) = ((head)->cqh_first);				\
+		(var) != CIRCLEQ_ENDC(head);				\
+		(var) = ((var)->field.cqe_next))
+
+#define	CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
+	for ((var) = ((head)->cqh_last);				\
+		(var) != CIRCLEQ_ENDC(head);				\
+		(var) = ((var)->field.cqe_prev))
+
+/*
+ * Circular queue access methods.
+ */
+#define	CIRCLEQ_FIRST(head)		((head)->cqh_first)
+#define	CIRCLEQ_LAST(head)		((head)->cqh_last)
+/* For comparisons */
+#define	CIRCLEQ_ENDC(head)		(__launder_type(head))
+/* For assignments */
+#define	CIRCLEQ_END(head)		((void *)(head))
+#define	CIRCLEQ_NEXT(elm, field)	((elm)->field.cqe_next)
+#define	CIRCLEQ_PREV(elm, field)	((elm)->field.cqe_prev)
+#define	CIRCLEQ_EMPTY(head)						\
+    (CIRCLEQ_FIRST(head) == CIRCLEQ_ENDC(head))
+
+#define CIRCLEQ_LOOP_NEXT(head, elm, field)				\
+	(((elm)->field.cqe_next == CIRCLEQ_ENDC(head))			\
+	    ? ((head)->cqh_first)					\
+	    : (elm->field.cqe_next))
+#define CIRCLEQ_LOOP_PREV(head, elm, field)				\
+	(((elm)->field.cqe_prev == CIRCLEQ_ENDC(head))			\
+	    ? ((head)->cqh_last)					\
+	    : (elm->field.cqe_prev))
+#endif /* !_KERNEL */
+
+#endif	/* !_SYS_QUEUE_H_ */
diff --git a/package/sys-queue/sys-queue.mk b/package/sys-queue/sys-queue.mk
new file mode 100644
index 000000000000..053ef8fd9e0d
--- /dev/null
+++ b/package/sys-queue/sys-queue.mk
@@ -0,0 +1,23 @@ 
+################################################################################
+#
+# sys-queue
+#
+################################################################################
+
+# source included in buildroot
+SYS_QUEUE_SOURCE =
+SYS_QUEUE_VERSION = 1.70
+
+SYS_QUEUE_LICENSE = BSD
+SYS_QUEUE_LICENSE_FILES = queue.h
+
+SYS_QUEUE_INSTALL_STAGING = YES
+
+define SYS_QUEUE_INSTALL_STAGING_CMDS
+	if [ ! -f $(STAGING_DIR)/usr/include/sys/queue.h ]; then \
+		$(INSTALL) -D -m 0644 package/sys-queue/queue.h \
+			$(STAGING_DIR)/usr/include/sys/queue.h; \
+	fi
+endef
+
+$(eval $(generic-package))
diff --git a/toolchain/toolchain-external/toolchain-external.mk b/toolchain/toolchain-external/toolchain-external.mk
index 613ce506608b..6b7d8021fe85 100644
--- a/toolchain/toolchain-external/toolchain-external.mk
+++ b/toolchain/toolchain-external/toolchain-external.mk
@@ -237,6 +237,13 @@  TOOLCHAIN_EXTERNAL_CFLAGS += -msoft-float
 TOOLCHAIN_EXTERNAL_TOOLCHAIN_WRAPPER_ARGS += -DBR_SOFTFLOAT=1
 endif
 
+# musl does not provide a sys/queue.h implementation, so add the
+# sys-queue package that will install a sys/queue.h file in the
+# staging directory based on the NetBSD implementation.
+ifeq ($(BR2_TOOLCHAIN_USES_MUSL),y)
+TOOLCHAIN_EXTERNAL_DEPENDENCIES += sys-queue
+endif
+
 # The Linaro ARMhf toolchain expects the libraries in
 # {/usr,}/lib/arm-linux-gnueabihf, but Buildroot copies them to
 # {/usr,}/lib, so we need to create a symbolic link.