[alsa-devel] Possible GPL-licensed header included in alsa-lib
Hi,
I recently reviewed the alsa-lib 1.0.27.2 source code from a licensing perspective to ensure compliant usage and distribution. It seems the intention is for the libraries to be covered by LGPL.
I had a look at include/list.h, which seems to be licensed under GPL-2.0. It does not have a license header or any other copyright information, but it states it was taken from Linux 2.4.0:
include/list.h, line 5: | This code was taken from the Linux 2.4.0 kernel. [jaroslav]
I'm not sure one could argue that the header was trivial, especially since it does not only contain constants, structures and interface definitions, but also implementations of inline functions.
I found one previous inquiry about a similar issue[1], but it does not cover the include/list.h header.
Two questions: 1. Have the copyright holders of the code in question agreed to re-license under a different, LGPL-preserving license and, if yes, is there some documentation about that? 2. If the header is indeed covered by GPL-2.0, would you accept patches to replace it with a different implementation, e.g. Rusty Russell's MIT-licensed list from ccan[2]?
[1] http://mailman.alsa-project.org/pipermail/alsa-devel/2011-March/038267.html [2] http://ccodearchive.net/info/list.html
Thank you for your time, Clemens Lang
Dne 9.12.2014 v 18:49 Clemens Lang napsal(a):
Hi,
I recently reviewed the alsa-lib 1.0.27.2 source code from a licensing perspective to ensure compliant usage and distribution. It seems the intention is for the libraries to be covered by LGPL.
I had a look at include/list.h, which seems to be licensed under GPL-2.0. It does not have a license header or any other copyright information, but it states it was taken from Linux 2.4.0:
include/list.h, line 5: | This code was taken from the Linux 2.4.0 kernel. [jaroslav]
I'm not sure one could argue that the header was trivial, especially since it does not only contain constants, structures and interface definitions, but also implementations of inline functions.
Fro my view, it's really trivial, but ...
I found one previous inquiry about a similar issue[1], but it does not cover the include/list.h header.
Two questions:
- Have the copyright holders of the code in question agreed to re-license under a different, LGPL-preserving license and, if yes,
is there some documentation about that?
I don't think so.. Not sure how difficult would be to gather the original authors from the 2.4 code.
- If the header is indeed covered by GPL-2.0, would you accept patches to replace it with a different implementation, e.g. Rusty Russell's
MIT-licensed list from ccan[2]?
It could be solution, but the current code seems a bit less complicated.
Could you try to obtain list of original authors from linux 2.4 ? I think I can ask about the licence change.
Thanks, Jaroslav
[1] http://mailman.alsa-project.org/pipermail/alsa-devel/2011-March/038267.html [2] http://ccodearchive.net/info/list.html
Thank you for your time, Clemens Lang
On Tue, Dec 09, 2014 at 07:40:07PM +0100, Jaroslav Kysela wrote:
Two questions:
- Have the copyright holders of the code in question agreed to re-license under a different, LGPL-preserving license and, if yes,
is there some documentation about that?
I don't think so.. Not sure how difficult would be to gather the original authors from the 2.4 code.
From what I can see the file appeared in 2.1.45. I haven't had enough
time to do so yet, but I will try looking into the lkml archives -- maybe I can find the patch that created it.
- If the header is indeed covered by GPL-2.0, would you accept patches to replace it with a different implementation, e.g. Rusty Russell's
MIT-licensed list from ccan[2]?
It could be solution, but the current code seems a bit less complicated.
I'm sure I could simplify the implementation and remove the features not needed by alsa.
Could you try to obtain list of original authors from linux 2.4 ? I think I can ask about the licence change.
I'm working on it and will get back to you once I have some results (or given up).
Best regards, Clemens
Hi,
On Thu, Dec 11, 2014 at 09:55:43AM +0100, Clemens Lang wrote:
- If the header is indeed covered by GPL-2.0, would you accept patches to replace it with a different implementation, e.g. Rusty Russell's
MIT-licensed list from ccan[2]?
It could be solution, but the current code seems a bit less complicated.
I'm sure I could simplify the implementation and remove the features not needed by alsa.
Could you try to obtain list of original authors from linux 2.4 ? I think I can ask about the licence change.
I'm working on it and will get back to you once I have some results (or given up).
as a follow-up, I have searched the lkml archives as published on lkml.org for 1996 and 1997 (where list.h appeared), but did not find a patch that contributed a list.h file or any of the functions in the file. So either the mail archive published at lmkl.org is incomplete, or the file was never sent to lmkl (written by Linus?).
Clemens
Hi,
the current implementation of include/list.h is taken from Linux 2.4.0 and possibly licensed under GPL-2.0. If the implementation isn't trivial, this might make libasound a derivative work and extend the viral effect to clients of the library. See http://mailman.alsa-project.org/pipermail/alsa-devel/2014-December/085261.ht... http://mailman.alsa-project.org/pipermail/alsa-devel/2014-December/085262.ht... http://mailman.alsa-project.org/pipermail/alsa-devel/2014-December/085325.ht... http://mailman.alsa-project.org/pipermail/alsa-devel/2015-January/086754.htm... for previous discussion.
This patch series avoids this ambiguity by replacing the list implementation with a version I modified from Rusty Russell's MIT-licensed list at http://ccodearchive.net/info/list.html
The two patches replace the list implementation and adapt the alsa-lib code accordingly. They are intended to be squashed together when merging.
[PATCH 1/2] Replace list.h with MIT-licensed implementation [PATCH 2/2] Adapt to changes in the linked list API
The previous linked list implementation in include/list.h was taken from Linux 2.4.0 and is thus likely licensed under GPL-2. If one does not consider the implementation trivial and the license actually applies, that might make libasound a derivative work, invoking the GPL's viral effect. This would make libasound unusable for any program that is not licensed under a GPL-compatible license.
Avoid any ambiguity in this regard by replacing the list with an MIT-licensed implementation with similar API originally written by Rusty Russell and adapted for alsa-libs. The original implementation is available from http://ccodearchive.net/info/list.html
Since the implementation uses typeof() when available, adjust configure to check for it.
See http://mailman.alsa-project.org/pipermail/alsa-devel/2014-December/085261.ht... http://mailman.alsa-project.org/pipermail/alsa-devel/2014-December/085262.ht... http://mailman.alsa-project.org/pipermail/alsa-devel/2014-December/085325.ht... http://mailman.alsa-project.org/pipermail/alsa-devel/2015-January/086754.htm... for the discussion around this change.
Signed-off-by: Clemens Lang clemens.lang@bmw-carit.de --- configure.ac | 1 + include/ccan_build_assert.h | 154 +++++++++++ include/ccan_check_type.h | 178 ++++++++++++ include/ccan_container_of.h | 259 ++++++++++++++++++ include/list.h | 649 +++++++++++++++++++++++++++++++++++++------- 5 files changed, 1138 insertions(+), 103 deletions(-) create mode 100644 include/ccan_build_assert.h create mode 100644 include/ccan_check_type.h create mode 100644 include/ccan_container_of.h
diff --git a/configure.ac b/configure.ac index 9621d4e..be62b83 100644 --- a/configure.ac +++ b/configure.ac @@ -61,6 +61,7 @@ AC_CONFIG_HEADERS(include/config.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE +AC_C_TYPEOF AC_HEADER_TIME
dnl Checks for library functions. diff --git a/include/ccan_build_assert.h b/include/ccan_build_assert.h new file mode 100644 index 0000000..56160a9 --- /dev/null +++ b/include/ccan_build_assert.h @@ -0,0 +1,154 @@ +/* + * Routines for build-time assertions + * Author: Rusty Russell rusty@rustcorp.com.au + * From http://ccodearchive.net/info/build_assert.html + * License: CC0 1.0 Universal (http://creativecommons.org/publicdomain/zero/1.0/legalcode) + */ +/* +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of authorship +and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific works +("Commons") that the public can reliably and without fear of later claims of +infringement build upon, modify, incorporate in other works, reuse and +redistribute as freely as possible in any form whatsoever and for any purposes, +including without limitation commercial purposes. These owners may contribute to +the Commons to promote the ideal of a free culture and the further production of +creative, cultural and scientific works, or to gain reputation or greater +distribution for their Work in part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any expectation of +additional consideration or compensation, the person associating CC0 with a Work +(the "Affirmer"), to the extent that he or she is an owner of Copyright and +Related Rights in the Work, voluntarily elects to apply CC0 to the Work and +publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be + protected by copyright and related or neighboring rights ("Copyright and + Related Rights"). Copyright and Related Rights include, but are not limited + to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations + thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, + applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and + unconditionally waives, abandons, and surrenders all of Affirmer's Copyright + and Related Rights and associated claims and causes of action, whether now + known or unknown (including existing as well as future claims and causes of + action), in the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the "Waiver"). Affirmer + makes the Waiver for the benefit of each member of the public at large and to + the detriment of Affirmer's heirs and successors, fully intending that such + Waiver shall not be subject to revocation, rescission, cancellation, + termination, or any other legal or equitable action to disrupt the quiet + enjoyment of the Work by the public as contemplated by Affirmer's express + Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be + judged legally invalid or ineffective under applicable law, then the Waiver + shall be preserved to the maximum extent permitted taking into account + Affirmer's express Statement of Purpose. In addition, to the extent the + Waiver is so judged Affirmer hereby grants to each affected person + a royalty-free, non transferable, non sublicensable, non exclusive, + irrevocable and unconditional license to exercise Affirmer's Copyright and + Related Rights in the Work (i) in all territories worldwide, (ii) for the + maximum duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the "License"). The License + shall be deemed effective as of the date CC0 was applied by Affirmer to the + Work. Should any part of the License for any reason be judged legally invalid + or ineffective under applicable law, such partial invalidity or + ineffectiveness shall not invalidate the remainder of the License, and in + such case Affirmer hereby affirms that he or she will not (i) exercise any of + his or her remaining Copyright and Related Rights in the Work or (ii) assert + any associated claims and causes of action with respect to the Work, in + either case contrary to Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness + for a particular purpose, non infringement, or the absence of latent or + other defects, accuracy, or the present or absence of errors, whether or + not discoverable, all to the greatest extent permissible under applicable + law. + + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. Further, + Affirmer disclaims responsibility for obtaining any necessary consents, + permissions or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a party + to this document and has no duty or obligation with respect to this CC0 or + use of the Work. +*/ +#ifndef CCAN_BUILD_ASSERT_H +#define CCAN_BUILD_ASSERT_H + +/** + * BUILD_ASSERT - assert a build-time dependency. + * @cond: the compile-time condition which must be true. + * + * Your compile will fail if the condition isn't true, or can't be evaluated + * by the compiler. This can only be used within a function. + * + * Example: + * #include <stddef.h> + * ... + * static char *foo_to_char(struct foo *foo) + * { + * // This code needs string to be at start of foo. + * BUILD_ASSERT(offsetof(struct foo, string) == 0); + * return (char *)foo; + * } + */ +#define BUILD_ASSERT(cond) \ + do { (void) sizeof(char [1 - 2*!(cond)]); } while(0) + +/** + * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression. + * @cond: the compile-time condition which must be true. + * + * Your compile will fail if the condition isn't true, or can't be evaluated + * by the compiler. This can be used in an expression: its value is "0". + * + * Example: + * #define foo_to_char(foo) \ + * ((char *)(foo) \ + * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0)) + */ +#define BUILD_ASSERT_OR_ZERO(cond) \ + (sizeof(char [1 - 2*!(cond)]) - 1) + +#endif /* CCAN_BUILD_ASSERT_H */ diff --git a/include/ccan_check_type.h b/include/ccan_check_type.h new file mode 100644 index 0000000..f957630 --- /dev/null +++ b/include/ccan_check_type.h @@ -0,0 +1,178 @@ +/* + * Routines for compile time type checking + * Author: Rusty Russell rusty@rustcorp.com.au + * From http://ccodearchive.net/info/check_type.html + * License: CC0 1.0 Universal (http://creativecommons.org/publicdomain/zero/1.0/legalcode) + */ +/* +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of authorship +and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific works +("Commons") that the public can reliably and without fear of later claims of +infringement build upon, modify, incorporate in other works, reuse and +redistribute as freely as possible in any form whatsoever and for any purposes, +including without limitation commercial purposes. These owners may contribute to +the Commons to promote the ideal of a free culture and the further production of +creative, cultural and scientific works, or to gain reputation or greater +distribution for their Work in part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any expectation of +additional consideration or compensation, the person associating CC0 with a Work +(the "Affirmer"), to the extent that he or she is an owner of Copyright and +Related Rights in the Work, voluntarily elects to apply CC0 to the Work and +publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be + protected by copyright and related or neighboring rights ("Copyright and + Related Rights"). Copyright and Related Rights include, but are not limited + to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations + thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, + applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and + unconditionally waives, abandons, and surrenders all of Affirmer's Copyright + and Related Rights and associated claims and causes of action, whether now + known or unknown (including existing as well as future claims and causes of + action), in the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the "Waiver"). Affirmer + makes the Waiver for the benefit of each member of the public at large and to + the detriment of Affirmer's heirs and successors, fully intending that such + Waiver shall not be subject to revocation, rescission, cancellation, + termination, or any other legal or equitable action to disrupt the quiet + enjoyment of the Work by the public as contemplated by Affirmer's express + Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be + judged legally invalid or ineffective under applicable law, then the Waiver + shall be preserved to the maximum extent permitted taking into account + Affirmer's express Statement of Purpose. In addition, to the extent the + Waiver is so judged Affirmer hereby grants to each affected person + a royalty-free, non transferable, non sublicensable, non exclusive, + irrevocable and unconditional license to exercise Affirmer's Copyright and + Related Rights in the Work (i) in all territories worldwide, (ii) for the + maximum duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the "License"). The License + shall be deemed effective as of the date CC0 was applied by Affirmer to the + Work. Should any part of the License for any reason be judged legally invalid + or ineffective under applicable law, such partial invalidity or + ineffectiveness shall not invalidate the remainder of the License, and in + such case Affirmer hereby affirms that he or she will not (i) exercise any of + his or her remaining Copyright and Related Rights in the Work or (ii) assert + any associated claims and causes of action with respect to the Work, in + either case contrary to Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness + for a particular purpose, non infringement, or the absence of latent or + other defects, accuracy, or the present or absence of errors, whether or + not discoverable, all to the greatest extent permissible under applicable + law. + + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. Further, + Affirmer disclaims responsibility for obtaining any necessary consents, + permissions or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a party + to this document and has no duty or obligation with respect to this CC0 or + use of the Work. +*/ +#ifndef CCAN_CHECK_TYPE_H +#define CCAN_CHECK_TYPE_H +#include "config.h" + +/** + * check_type - issue a warning or build failure if type is not correct. + * @expr: the expression whose type we should check (not evaluated). + * @type: the exact type we expect the expression to be. + * + * This macro is usually used within other macros to try to ensure that a macro + * argument is of the expected type. No type promotion of the expression is + * done: an unsigned int is not the same as an int! + * + * check_type() always evaluates to 0. + * + * If your compiler does not support typeof, then the best we can do is fail + * to compile if the sizes of the types are unequal (a less complete check). + * + * Example: + * // They should always pass a 64-bit value to _set_some_value! + * #define set_some_value(expr) \ + * _set_some_value((check_type((expr), uint64_t), (expr))) + */ + +/** + * check_types_match - issue a warning or build failure if types are not same. + * @expr1: the first expression (not evaluated). + * @expr2: the second expression (not evaluated). + * + * This macro is usually used within other macros to try to ensure that + * arguments are of identical types. No type promotion of the expressions is + * done: an unsigned int is not the same as an int! + * + * check_types_match() always evaluates to 0. + * + * If your compiler does not support typeof, then the best we can do is fail + * to compile if the sizes of the types are unequal (a less complete check). + * + * Example: + * // Do subtraction to get to enclosing type, but make sure that + * // pointer is of correct type for that member. + * #define container_of(mbr_ptr, encl_type, mbr) \ + * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \ + * ((encl_type *) \ + * ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr)))) + */ +#if HAVE_TYPEOF +#define check_type(expr, type) \ + ((typeof(expr) *)0 != (type *)0) + +#define check_types_match(expr1, expr2) \ + ((typeof(expr1) *)0 != (typeof(expr2) *)0) +#else +#include <ccan_build_assert.h> +/* Without typeof, we can only test the sizes. */ +#define check_type(expr, type) \ + BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type)) + +#define check_types_match(expr1, expr2) \ + BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2)) +#endif /* HAVE_TYPEOF */ + +#endif /* CCAN_CHECK_TYPE_H */ diff --git a/include/ccan_container_of.h b/include/ccan_container_of.h new file mode 100644 index 0000000..1d92fd9 --- /dev/null +++ b/include/ccan_container_of.h @@ -0,0 +1,259 @@ +/* + * Routine for upcasting + * Author: Rusty Russell rusty@rustcorp.com.au + * From http://ccodearchive.net/info/container_of.html + * License: CC0 1.0 Universal (http://creativecommons.org/publicdomain/zero/1.0/legalcode) + */ +/* +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of authorship +and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific works +("Commons") that the public can reliably and without fear of later claims of +infringement build upon, modify, incorporate in other works, reuse and +redistribute as freely as possible in any form whatsoever and for any purposes, +including without limitation commercial purposes. These owners may contribute to +the Commons to promote the ideal of a free culture and the further production of +creative, cultural and scientific works, or to gain reputation or greater +distribution for their Work in part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any expectation of +additional consideration or compensation, the person associating CC0 with a Work +(the "Affirmer"), to the extent that he or she is an owner of Copyright and +Related Rights in the Work, voluntarily elects to apply CC0 to the Work and +publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be + protected by copyright and related or neighboring rights ("Copyright and + Related Rights"). Copyright and Related Rights include, but are not limited + to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations + thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, + applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and + unconditionally waives, abandons, and surrenders all of Affirmer's Copyright + and Related Rights and associated claims and causes of action, whether now + known or unknown (including existing as well as future claims and causes of + action), in the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the "Waiver"). Affirmer + makes the Waiver for the benefit of each member of the public at large and to + the detriment of Affirmer's heirs and successors, fully intending that such + Waiver shall not be subject to revocation, rescission, cancellation, + termination, or any other legal or equitable action to disrupt the quiet + enjoyment of the Work by the public as contemplated by Affirmer's express + Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be + judged legally invalid or ineffective under applicable law, then the Waiver + shall be preserved to the maximum extent permitted taking into account + Affirmer's express Statement of Purpose. In addition, to the extent the + Waiver is so judged Affirmer hereby grants to each affected person + a royalty-free, non transferable, non sublicensable, non exclusive, + irrevocable and unconditional license to exercise Affirmer's Copyright and + Related Rights in the Work (i) in all territories worldwide, (ii) for the + maximum duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the "License"). The License + shall be deemed effective as of the date CC0 was applied by Affirmer to the + Work. Should any part of the License for any reason be judged legally invalid + or ineffective under applicable law, such partial invalidity or + ineffectiveness shall not invalidate the remainder of the License, and in + such case Affirmer hereby affirms that he or she will not (i) exercise any of + his or her remaining Copyright and Related Rights in the Work or (ii) assert + any associated claims and causes of action with respect to the Work, in + either case contrary to Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness + for a particular purpose, non infringement, or the absence of latent or + other defects, accuracy, or the present or absence of errors, whether or + not discoverable, all to the greatest extent permissible under applicable + law. + + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. Further, + Affirmer disclaims responsibility for obtaining any necessary consents, + permissions or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a party + to this document and has no duty or obligation with respect to this CC0 or + use of the Work. +*/ +#ifndef CCAN_CONTAINER_OF_H +#define CCAN_CONTAINER_OF_H +#include <stddef.h> + +#include "config.h" +#include <ccan_check_type.h> + +/** + * container_of - get pointer to enclosing structure + * @member_ptr: pointer to the structure member + * @containing_type: the type this member is within + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does pointer + * subtraction to return the pointer to the enclosing type. + * + * Example: + * struct foo { + * int fielda, fieldb; + * // ... + * }; + * struct info { + * int some_other_field; + * struct foo my_foo; + * }; + * + * static struct info *foo_to_info(struct foo *foo) + * { + * return container_of(foo, struct info, my_foo); + * } + */ +#define container_of(member_ptr, containing_type, member) \ + ((containing_type *) \ + ((char *)(member_ptr) \ + - container_off(containing_type, member)) \ + + check_types_match(*(member_ptr), ((containing_type *)0)->member)) + + +/** + * container_of_or_null - get pointer to enclosing structure, or NULL + * @member_ptr: pointer to the structure member + * @containing_type: the type this member is within + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does pointer + * subtraction to return the pointer to the enclosing type, unless it + * is given NULL, in which case it also returns NULL. + * + * Example: + * struct foo { + * int fielda, fieldb; + * // ... + * }; + * struct info { + * int some_other_field; + * struct foo my_foo; + * }; + * + * static struct info *foo_to_info_allowing_null(struct foo *foo) + * { + * return container_of_or_null(foo, struct info, my_foo); + * } + */ +static inline char *container_of_or_null_(void *member_ptr, size_t offset) +{ + return member_ptr ? (char *)member_ptr - offset : NULL; +} +#define container_of_or_null(member_ptr, containing_type, member) \ + ((containing_type *) \ + container_of_or_null_(member_ptr, \ + container_off(containing_type, member)) \ + + check_types_match(*(member_ptr), ((containing_type *)0)->member)) + +/** + * container_off - get offset to enclosing structure + * @containing_type: the type this member is within + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does + * typechecking and figures out the offset to the enclosing type. + * + * Example: + * struct foo { + * int fielda, fieldb; + * // ... + * }; + * struct info { + * int some_other_field; + * struct foo my_foo; + * }; + * + * static struct info *foo_to_info(struct foo *foo) + * { + * size_t off = container_off(struct info, my_foo); + * return (void *)((char *)foo - off); + * } + */ +#define container_off(containing_type, member) \ + offsetof(containing_type, member) + +/** + * container_of_var - get pointer to enclosing structure using a variable + * @member_ptr: pointer to the structure member + * @container_var: a pointer of same type as this member's container + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does pointer + * subtraction to return the pointer to the enclosing type. + * + * Example: + * static struct info *foo_to_i(struct foo *foo) + * { + * struct info *i = container_of_var(foo, i, my_foo); + * return i; + * } + */ +#if HAVE_TYPEOF +#define container_of_var(member_ptr, container_var, member) \ + container_of(member_ptr, typeof(*container_var), member) +#else +#define container_of_var(member_ptr, container_var, member) \ + ((void *)((char *)(member_ptr) - \ + container_off_var(container_var, member))) +#endif + +/** + * container_off_var - get offset of a field in enclosing structure + * @container_var: a pointer to a container structure + * @member: the name of a member within the structure. + * + * Given (any) pointer to a structure and a its member name, this + * macro does pointer subtraction to return offset of member in a + * structure memory layout. + * + */ +#if HAVE_TYPEOF +#define container_off_var(var, member) \ + container_off(typeof(*var), member) +#else +#define container_off_var(var, member) \ + ((const char *)&(var)->member - (const char *)(var)) +#endif + +#endif /* CCAN_CONTAINER_OF_H */ diff --git a/include/list.h b/include/list.h index 4d9895f..a322361 100644 --- a/include/list.h +++ b/include/list.h @@ -1,174 +1,617 @@ -#ifndef _LIST_H -#define _LIST_H - /* - * This code was taken from the Linux 2.4.0 kernel. [jaroslav] + * Double linked list routines + * Author: Rusty Russell rusty@rustcorp.com.au + * From http://ccodearchive.net/info/list.html + * License: MIT + * + * Modified for use in alsa-libs by Clemens Lang clemens.lang@bmw-carit.de */ - /* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#ifndef CCAN_LIST_H +#define CCAN_LIST_H +#include <stdbool.h> +#include <assert.h> +#include <ccan_container_of.h> +#include <ccan_check_type.h>
-#ifndef LIST_HEAD_IS_DEFINED -struct list_head { +/** + * struct list_head - an entry in a doubly-linked list + * @next: next entry (self if empty) + * @prev: previous entry (self if empty) + * + * This is used as an entry in and head of a linked list. + * Example: + * struct child { + * const char *name; + * // Linked list of all us children. + * struct list_head list; + * }; + */ +struct list_head +{ struct list_head *next, *prev; }; -#endif
+/** + * LIST_HEAD_INIT - initializer for an empty list_head + * @name: the name of the list. + * + * Explicit initializer for an empty list. + * + * See also: + * LIST_HEAD, list_head_init() + * + * Example: + * static struct list_head my_list = LIST_HEAD_INIT(my_list); + */ #define LIST_HEAD_INIT(name) { &(name), &(name) }
+/** + * LIST_HEAD - define and initialize an empty list_head + * @name: the name of the list. + * + * The LIST_HEAD macro defines a list_head and initializes it to an empty + * list. It can be prepended by "static" to define a static list_head. + * + * See also: + * INIT_LIST_HEAD, list_head_init() + * + * Example: + * static LIST_HEAD(my_global_list); + */ #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name)
-#define INIT_LIST_HEAD(ptr) do { \ - (ptr)->next = (ptr); (ptr)->prev = (ptr); \ -} while (0) +/** + * list_head_init - initialize a list_head + * @h: the list_head to set to the empty list + * + * Example: + * ... + * struct parent *parent = malloc(sizeof(*parent)); + * + * list_head_init(&parent->children); + * parent->num_children = 0; + */ +static inline void list_head_init(struct list_head *h) +{ + h->next = h->prev = h; +} +#define INIT_LIST_HEAD(x) list_head_init(x)
-/* - * Insert a new entry between two known consecutive entries. +/** + * list_add - add an entry at the start of a linked list. + * @h: the list_head to add the node to + * @n: the list_head to add to the list. * - * This is only for internal list manipulation where we know - * the prev/next entries already! + * The list node does not need to be initialized; it will be overwritten. + * Example: + * struct child *child = malloc(sizeof(*child)); + * + * child->name = "marvin"; + * list_add(&parent->children, &child->list); + * parent->num_children++; */ -static __inline__ void __list_add(struct list_head * _new, - struct list_head * prev, - struct list_head * next) +static inline void list_add(struct list_head *h, + struct list_head *n) { - next->prev = _new; - _new->next = next; - _new->prev = prev; - prev->next = _new; + n->next = h->next; + n->prev = h; + h->next->prev = n; + h->next = n; }
/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after + * list_add_tail - add an entry at the end of a linked list. + * @n: the list_head to add to the list. + * @h: the list_head to add the node to * - * Insert a new entry after the specified head. - * This is good for implementing stacks. + * The list node does not need to be initialized; it will be overwritten. + * Example: + * list_add_tail(&child->list, &parent->children); + * parent->num_children++; */ -static __inline__ void list_add(struct list_head *_new, struct list_head *head) +static inline void list_add_tail(struct list_head *n, + struct list_head *h) { - __list_add(_new, head, head->next); + n->next = h; + n->prev = h->prev; + h->prev->next = n; + h->prev = n; }
/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before + * list_empty - is a list empty? + * @h: the list_head + * + * If the list is empty, returns true. * - * Insert a new entry before the specified head. - * This is useful for implementing queues. + * Example: + * assert(list_empty(&parent->children) == (parent->num_children == 0)); */ -static __inline__ void list_add_tail(struct list_head *_new, struct list_head *head) +static inline bool list_empty(const struct list_head *h) { - __list_add(_new, head->prev, head); + return h->next == h; }
-/* - * Delete a list entry by making the prev/next entries - * point to each other. +/** + * list_del - delete an entry from an (unknown) linked list. + * @n: the list_head to delete from the list. * - * This is only for internal list manipulation where we know - * the prev/next entries already! + * Note that this leaves @n in an undefined state; it can be added to + * another list, but not deleted again. + * + * See also: + * list_del_from(), list_del_init() + * + * Example: + * list_del(&child->list); + * parent->num_children--; */ -static __inline__ void __list_del(struct list_head * prev, - struct list_head * next) +static inline void list_del(struct list_head *n) { - next->prev = prev; - prev->next = next; + n->next->prev = n->prev; + n->prev->next = n->next; }
/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty on entry does not return true after this, the entry is in an undefined state. + * list_del_init - delete a node, and reset it so it can be deleted again. + * @n: the list_head to be deleted. + * + * list_del(@n) or list_del_init() again after this will be safe, + * which can be useful in some cases. + * + * See also: + * list_del_from(), list_del() + * + * Example: + * list_del_init(&child->list); + * parent->num_children--; */ -static __inline__ void list_del(struct list_head *entry) +static inline void list_del_init(struct list_head *n) { - __list_del(entry->prev, entry->next); + list_del(n); + list_head_init(n); }
/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list.n + * list_del_from - delete an entry from a known linked list. + * @h: the list_head the node is in. + * @n: the list_head to delete from the list. + * + * This explicitly indicates which list a node is expected to be in, + * which is better documentation and can catch more bugs. + * + * See also: list_del() + * + * Example: + * list_del_from(&parent->children, &child->list); + * parent->num_children--; */ -static __inline__ void list_del_init(struct list_head *entry) +static inline void list_del_from(struct list_head *h, struct list_head *n) { - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); + /* Quick test that catches a surprising number of bugs. */ + assert(!list_empty(h)); + list_del(n); }
/** - * list_empty - tests whether a list is empty - * @head: the list to test. + * list_entry - convert a list_head back into the structure containing it. + * @n: the list_head + * @type: the type of the entry + * @member: the list_head member of the type + * + * Example: + * // First list entry is children.next; convert back to child. + * child = list_entry(parent->children.next, struct child, list); + * + * See Also: + * list_top(), list_for_each() + */ +#define list_entry(n, type, member) container_of(n, type, member) + +/** + * list_top - get the first entry in a list + * @h: the list_head + * @type: the type of the entry + * @member: the list_head member of the type + * + * If the list is empty, returns NULL. + * + * Example: + * struct child *first; + * first = list_top(&parent->children, struct child, list); + * if (!first) + * printf("Empty list!\n"); */ -static __inline__ int list_empty(struct list_head *head) +#define list_top(h, type, member) \ + ((type *)list_top_((h), list_off_(type, member))) + +static inline const void *list_top_(const struct list_head *h, size_t off) { - return head->next == head; + if (list_empty(h)) + return NULL; + return (const char *)h->next - off; }
/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. + * list_pop - remove the first entry in a list + * @h: the list_head + * @type: the type of the entry + * @member: the list_head member of the type + * + * If the list is empty, returns NULL. + * + * Example: + * struct child *one; + * one = list_pop(&parent->children, struct child, list); + * if (!one) + * printf("Empty list!\n"); */ -static __inline__ void list_splice(struct list_head *list, struct list_head *head) +#define list_pop(h, type, member) \ + ((type *)list_pop_((h), list_off_(type, member))) + +static inline const void *list_pop_(const struct list_head *h, size_t off) { - struct list_head *first = list->next; + struct list_head *n;
- if (first != list) { - struct list_head *last = list->prev; - struct list_head *at = head->next; + if (list_empty(h)) + return NULL; + n = h->next; + list_del(n); + return (const char *)n - off; +}
- first->prev = head; - head->next = first; +/** + * list_tail - get the last entry in a list + * @h: the list_head + * @type: the type of the entry + * @member: the list_head member of the type + * + * If the list is empty, returns NULL. + * + * Example: + * struct child *last; + * last = list_tail(&parent->children, struct child, list); + * if (!last) + * printf("Empty list!\n"); + */ +#define list_tail(h, type, member) \ + ((type *)list_tail_((h), list_off_(type, member)))
- last->next = at; - at->prev = last; - } +static inline const void *list_tail_(const struct list_head *h, size_t off) +{ + if (list_empty(h)) + return NULL; + return (const char *)h->prev - off; }
/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. + * list_for_each - iterate through a list. + * @h: the list_head (warning: evaluated multiple times!) + * @i: the structure containing the list_head + * @member: the list_head member of the structure + * + * This is a convenient wrapper to iterate @i over the entire list. It's + * a for loop, so you can break and continue as normal. + * + * Example: + * list_for_each(&parent->children, child, list) + * printf("Name: %s\n", child->name); + */ +#define list_for_each(h, i, member) \ + list_for_each_off(h, i, list_off_var_(i, member)) + +/** + * list_for_each_raw - iterate through a list and return the list node struct + * rather than the list element. + * @h: the list_head (warning: evaluated multiple times!) + * @i: the structure containing the list_head + * + * This is a convenient wrapper to iterate @i over the entire list. It's + * a for loop, so you can break and continue as normal. + * + * Example: + * struct list_head *node; + * list_for_each_raw(&parent->children, node) { + * struct child *child = list_entry(node, struct child, list); + * printf("Name: %s\n", child->name); + * } + */ +#define list_for_each_raw(h, i) \ + for (i = (h)->next; i != (h); i = (h)->next) + +/** + * list_for_each_rev - iterate through a list backwards. + * @h: the list_head + * @i: the structure containing the list_head + * @member: the list_head member of the structure + * + * This is a convenient wrapper to iterate @i over the entire list. It's + * a for loop, so you can break and continue as normal. + * + * Example: + * list_for_each_rev(&parent->children, child, list) + * printf("Name: %s\n", child->name); */ -#define list_for_each(pos, head) \ - for (pos = (head)->next ; pos != (head); pos = pos->next) +#define list_for_each_rev(h, i, member) \ + for (i = container_of_var((h)->prev, i, member); \ + &i->member != (h); \ + i = container_of_var(i->member.prev, i, member))
/** - * list_for_each_safe - iterate over a list safely (actual pointer can be invalidated) - * @pos: the &struct list_head to use as a loop counter. - * @next: the &struct list_head to use to save next. - * @head: the head for your list. + * list_for_each_safe - iterate through a list, maybe during deletion + * @h: the list_head + * @i: the structure containing the list_head + * @nxt: the structure containing the list_head + * @member: the list_head member of the structure + * + * This is a convenient wrapper to iterate @i over the entire list. It's + * a for loop, so you can break and continue as normal. The extra variable + * @nxt is used to hold the next element, so you can delete @i from the list. + * + * Example: + * struct child *next; + * list_for_each_safe(&parent->children, child, next, list) { + * list_del(&child->list); + * parent->num_children--; + * } */ -#define list_for_each_safe(pos, npos, head) \ - for (pos = (head)->next, npos = pos->next ; pos != (head); pos = npos, npos = pos->next) +#define list_for_each_safe(h, i, nxt, member) \ + list_for_each_safe_off(h, i, nxt, list_off_var_(i, member))
/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. + * list_for_each_raw_safe - iterate through a list, maybe during deletion, and + * return the list node struct rather than the list element. + * @h: the list_head + * @i: the structure containing the list_head + * @nxt: the structure containing the list_head + * + * This is a convenient wrapper to iterate @i over the entire list. It's + * a for loop, so you can break and continue as normal. The extra variable + * @nxt is used to hold the next element, so you can delete @i from the list. + * + * Example: + * struct list_head *node; + * struct list_head *next; + * list_for_each_raw_safe(&parent->children, node, next) { + * struct child *child = list_entry(node, struct child, list); + * printf("deleting Name: %s\n", child->name); + * list_del(node); + * } */ -#define list_entry(ptr, type, member) \ - ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) +#define list_for_each_raw_safe(h, i, nxt) \ + for (i = (h)->next, nxt = i->next; \ + i != (h); i = nxt, nxt = i->next)
/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @offset: offset of entry inside a struct + * list_next - get the next entry in a list + * @h: the list_head + * @i: a pointer to an entry in the list. + * @member: the list_head member of the structure + * + * If @i was the last entry in the list, returns NULL. + * + * Example: + * struct child *second; + * second = list_next(&parent->children, first, list); + * if (!second) + * printf("No second child!\n"); + */ +#define list_next(h, i, member) \ + ((list_typeof(i))list_entry_or_null(h, \ + (i)->member.next, \ + list_off_var_((i), member))) + +/** + * list_prev - get the previous entry in a list + * @h: the list_head + * @i: a pointer to an entry in the list. + * @member: the list_head member of the structure + * + * If @i was the first entry in the list, returns NULL. + * + * Example: + * first = list_prev(&parent->children, second, list); + * if (!first) + * printf("Can't go back to first child?!\n"); */ -#define list_entry_offset(ptr, type, offset) \ - ((type *)((char *)(ptr)-(offset))) +#define list_prev(h, i, member) \ + ((list_typeof(i))list_entry_or_null(h, \ + (i)->member.prev, \ + list_off_var_((i), member))) + +/** + * list_append_list - empty one list onto the end of another. + * @to: the list to append into + * @from: the list to empty. + * + * This takes the entire contents of @from and moves it to the end of + * @to. After this @from will be empty. + * + * Example: + * struct list_head adopter; + * + * list_append_list(&adopter, &parent->children); + * assert(list_empty(&parent->children)); + * parent->num_children = 0; + */ +static inline void list_append_list_(struct list_head *to, + struct list_head *from) +{ + struct list_head *from_tail = from->prev; + struct list_head *to_tail = to->prev; + + /* Sew in head and entire list. */ + to->prev = from_tail; + from_tail->next = to; + to_tail->next = from; + from->prev = to_tail; + + /* Now remove head. */ + list_del(from); + list_head_init(from); +} + +/** + * list_prepend_list - empty one list into the start of another. + * @to: the list to prepend into + * @from: the list to empty. + * + * This takes the entire contents of @from and moves it to the start + * of @to. After this @from will be empty. + * + * Example: + * list_prepend_list(&adopter, &parent->children); + * assert(list_empty(&parent->children)); + * parent->num_children = 0; + */ +static inline void list_prepend_list_(struct list_head *to, + struct list_head *from) +{ + struct list_head *from_tail = from->prev; + struct list_head *to_head = to->next; + + /* Sew in head and entire list. */ + to->next = from; + from->prev = to; + to_head->prev = from_tail; + from_tail->next = to_head;
-#endif /* _LIST_H */ + /* Now remove head. */ + list_del(from); + list_head_init(from); +} + +/** + * list_for_each_off - iterate through a list of memory regions. + * @h: the list_head + * @i: the pointer to a memory region wich contains list node data. + * @off: offset(relative to @i) at which list node data resides. + * + * This is a low-level wrapper to iterate @i over the entire list, used to + * implement all oher, more high-level, for-each constructs. It's a for loop, + * so you can break and continue as normal. + * + * WARNING! Being the low-level macro that it is, this wrapper doesn't know + * nor care about the type of @i. The only assumtion made is that @i points + * to a chunk of memory that at some @offset, relative to @i, contains a + * properly filled `struct node_list' which in turn contains pointers to + * memory chunks and it's turtles all the way down. Whith all that in mind + * remember that given the wrong pointer/offset couple this macro will + * happilly churn all you memory untill SEGFAULT stops it, in other words + * caveat emptor. + * + * It is worth mentioning that one of legitimate use-cases for that wrapper + * is operation on opaque types with known offset for `struct list_head' + * member(preferably 0), because it allows you not to disclose the type of + * @i. + * + * Example: + * list_for_each_off(&parent->children, child, + * offsetof(struct child, list)) + * printf("Name: %s\n", child->name); + */ +#define list_for_each_off(h, i, off) \ + for (i = list_node_to_off_((h)->next, (off)); \ + list_node_from_off_((void *)i, (off)) != (h); \ + i = list_node_to_off_(list_node_from_off_((void *)i, (off))->next, \ + (off))) + +/** + * list_for_each_safe_off - iterate through a list of memory regions, maybe + * during deletion + * @h: the list_head + * @i: the pointer to a memory region wich contains list node data. + * @nxt: the structure containing the list_head + * @off: offset(relative to @i) at which list node data resides. + * + * For details see `list_for_each_off' and `list_for_each_safe' + * descriptions. + * + * Example: + * list_for_each_safe_off(&parent->children, child, + * next, offsetof(struct child, list)) + * printf("Name: %s\n", child->name); + */ +#define list_for_each_safe_off(h, i, nxt, off) \ + for (i = list_node_to_off_((h)->next, (off)), \ + nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \ + (off)); \ + list_node_from_off_(i, (off)) != (h); \ + i = nxt, \ + nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \ + (off))) + + +/* Other -off variants. */ +#define list_entry_off(n, type, off) \ + ((type *)list_node_from_off_((n), (off))) + +#define list_head_off(h, type, off) \ + ((type *)list_head_off((h), (off))) + +#define list_tail_off(h, type, off) \ + ((type *)list_tail_((h), (off))) + +#define list_add_off(h, n, off) \ + list_add((h), list_node_from_off_((n), (off))) + +#define list_del_off(n, off) \ + list_del(list_node_from_off_((n), (off))) + +#define list_del_from_off(h, n, off) \ + list_del_from(h, list_node_from_off_((n), (off))) + +/* Offset helper functions so we only single-evaluate. */ +static inline void *list_node_to_off_(struct list_head *node, size_t off) +{ + return (void *)((char *)node - off); +} +static inline struct list_head *list_node_from_off_(void *ptr, size_t off) +{ + return (struct list_head *)((char *)ptr + off); +} + +/* Get the offset of the member, but make sure it's a list_head. */ +#define list_off_(type, member) \ + (container_off(type, member) + \ + check_type(((type *)0)->member, struct list_head)) + +#define list_off_var_(var, member) \ + (container_off_var(var, member) + \ + check_type(var->member, struct list_head)) + +#if HAVE_TYPEOF +#define list_typeof(var) typeof(var) +#else +#define list_typeof(var) void * +#endif + +/* Returns member, or NULL if at end of list. */ +static inline void *list_entry_or_null(const struct list_head *h, + const struct list_head *n, + size_t off) +{ + if (n == h) + return NULL; + return (char *)n - off; +} +#endif /* CCAN_LIST_H */
Signed-off-by: Clemens Lang clemens.lang@bmw-carit.de --- aserver/aserver.c | 4 +- modules/mixer/simple/sbase.c | 36 +++++------------ src/alisp/alisp.c | 61 ++++++++-------------------- src/async.c | 5 +-- src/control/control.c | 2 +- src/control/setup.c | 10 ++--- src/dlmisc.c | 16 +++----- src/mixer/bag.c | 5 +-- src/mixer/mixer.c | 64 ++++++++++------------------- src/mixer/mixer_local.h | 4 +- src/mixer/simple.c | 4 +- src/pcm/pcm_hooks.c | 22 +++++----- src/pcm/pcm_ladspa.c | 64 +++++++++++++---------------- src/pcm/pcm_meter.c | 31 +++++---------- src/pcm/pcm_share.c | 20 ++++------ src/shmarea.c | 4 +- src/ucm/main.c | 95 +++++++++++++------------------------------- src/ucm/utils.c | 42 +++++++------------- 18 files changed, 164 insertions(+), 325 deletions(-)
diff --git a/aserver/aserver.c b/aserver/aserver.c index 1579da7..696abb8 100644 --- a/aserver/aserver.c +++ b/aserver/aserver.c @@ -829,7 +829,6 @@ static int inet_pending_handler(waiter_t *waiter, unsigned short events) inet_pending_t *pdata; client_t *client; uint32_t cookie; - struct list_head *item; int remove = 0; if (events & POLLHUP) remove = 1; @@ -851,8 +850,7 @@ static int inet_pending_handler(waiter_t *waiter, unsigned short events) return 0; }
- list_for_each(item, &inet_pendings) { - pdata = list_entry(item, inet_pending_t, list); + list_for_each(&inet_pendings, pdata, list) { if (pdata->cookie == cookie) goto found; } diff --git a/modules/mixer/simple/sbase.c b/modules/mixer/simple/sbase.c index bb2f59d..838d2df 100644 --- a/modules/mixer/simple/sbase.c +++ b/modules/mixer/simple/sbase.c @@ -75,15 +75,13 @@ static void update_ranges(struct selem_base *s) static unsigned int mask[2] = { SM_CAP_PVOLUME, SM_CAP_CVOLUME }; static unsigned int gmask[2] = { SM_CAP_GVOLUME, SM_CAP_GVOLUME }; unsigned int dir, ok_flag; - struct list_head *pos; struct helem_base *helem; for (dir = 0; dir < 2; dir++) { s->dir[dir].min = 0; s->dir[dir].max = 0; ok_flag = 0; - list_for_each(pos, &s->helems) { - helem = list_entry(pos, struct helem_base, list); + list_for_each(&s->helems, helem, list) { printf("min = %li, max = %li\n", helem->min, helem->max); if (helem->caps & mask[dir]) { s->dir[dir].min = helem->min; @@ -94,8 +92,7 @@ static void update_ranges(struct selem_base *s) } if (ok_flag) continue; - list_for_each(pos, &s->helems) { - helem = list_entry(pos, struct helem_base, list); + list_for_each(&s->helems, helem, list) { if (helem->caps & gmask[dir]) { s->dir[dir].min = helem->min; s->dir[dir].max = helem->max; @@ -116,10 +113,8 @@ static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val) switch (cmd) {
case SM_OPS_IS_ACTIVE: { - struct list_head *pos; struct helem_base *helem; - list_for_each(pos, &s->helems) { - helem = list_entry(pos, struct helem_base, list); + list_for_each(&s->helems, helem, list) { if (helem->inactive) return 0; } @@ -301,13 +296,11 @@ static int simple_event_remove(snd_hctl_elem_t *helem, static void selem_free(snd_mixer_elem_t *elem) { struct selem_base *simple = snd_mixer_elem_get_private(elem); - struct helem_base *hsimple; - struct list_head *pos, *npos; + struct helem_base *hsimple, *nhsimple;
if (simple->selem.id) snd_mixer_selem_id_free(simple->selem.id); - list_for_each_safe(pos, npos, &simple->helems) { - hsimple = list_entry(pos, struct helem_base, list); + list_for_each_safe(&simple->helems, hsimple, nhsimple, list) { free(hsimple); } free(simple); @@ -327,13 +320,11 @@ static int simple_event_add1(snd_mixer_class_t *class, unsigned long values; long min, max; int err, new = 0; - struct list_head *pos; struct bclass_sid *bsid; struct melem_sids *sid; unsigned int ui; - list_for_each(pos, &priv->sids) { - bsid = list_entry(pos, struct bclass_sid, list); + list_for_each(&priv->sids, bsid, list) { for (ui = 0; ui < bsid->count; ui++) { if (bsid->sids[ui].sid == sel->sid) { sid = &bsid->sids[ui]; @@ -458,15 +449,13 @@ static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem) struct bclass_private *priv = snd_mixer_sbasic_get_private(class); struct bclass_selector *sel; struct helem_selector *hsel; - struct list_head *pos; snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem); const char *name = snd_hctl_elem_get_name(helem); unsigned int index = snd_hctl_elem_get_index(helem); unsigned int ui; int err;
- list_for_each(pos, &priv->selectors) { - sel = list_entry(pos, struct bclass_selector, list); + list_for_each(&priv->selectors, sel, list) { for (ui = 0; ui < sel->count; ui++) { hsel = &sel->selectors[ui]; if (hsel->iface == iface && !strcmp(hsel->name, name) && hsel->index == index) { @@ -515,16 +504,13 @@ int alsa_mixer_sbasic_event(snd_mixer_class_t *class, unsigned int mask, static void sbasic_cpriv_free(snd_mixer_class_t *class) { struct bclass_private *priv = snd_mixer_sbasic_get_private(class); - struct bclass_selector *sel; - struct bclass_sid *sid; - struct list_head *pos, *pos1; + struct bclass_selector *sel, *nsel; + struct bclass_sid *sid, *nsid;
- list_for_each_safe(pos, pos1, &priv->selectors) { - sel = list_entry(pos, struct bclass_selector, list); + list_for_each_safe(&priv->selectors, sel, nsel, list) { free(sel); } - list_for_each_safe(pos, pos1, &priv->sids) { - sid = list_entry(pos, struct bclass_sid, list); + list_for_each_safe(&priv->sids, sid, nsid, list) { free(sid); } free(priv); diff --git a/src/alisp/alisp.c b/src/alisp/alisp.c index 3c61bb1..ed71282 100644 --- a/src/alisp/alisp.c +++ b/src/alisp/alisp.c @@ -257,14 +257,12 @@ static struct alisp_object * incref_tree_explicit(struct alisp_instance *instanc
static void free_objects(struct alisp_instance *instance) { - struct list_head *pos, *pos1; - struct alisp_object * p; - struct alisp_object_pair * pair; + struct alisp_object * p, * pnext; + struct alisp_object_pair * pair, * pairnext; int i, j;
for (i = 0; i < ALISP_OBJ_PAIR_HASH_SIZE; i++) { - list_for_each_safe(pos, pos1, &instance->setobjs_list[i]) { - pair = list_entry(pos, struct alisp_object_pair, list); + list_for_each_safe(&instance->setobjs_list[i], pair, pairnext, list) { lisp_debug(instance, "freeing pair: '%s' -> %p", pair->name, pair->value); delete_tree(instance, pair->value); free((void *)pair->name); @@ -273,8 +271,7 @@ static void free_objects(struct alisp_instance *instance) } for (i = 0; i < ALISP_OBJ_PAIR_HASH_SIZE; i++) for (j = 0; j <= ALISP_OBJ_LAST_SEARCH; j++) { - list_for_each_safe(pos, pos1, &instance->used_objs_list[i][j]) { - p = list_entry(pos, struct alisp_object, list); + list_for_each_safe(&instance->used_objs_list[i][j], p, pnext, list) { lisp_warn(instance, "object %p is still referenced %i times!", p, alisp_get_refs(p)); #if 0 snd_output_printf(instance->wout, ">>>> "); @@ -286,8 +283,7 @@ static void free_objects(struct alisp_instance *instance) delete_object(instance, p); } } - list_for_each_safe(pos, pos1, &instance->free_objs_list) { - p = list_entry(pos, struct alisp_object, list); + list_for_each_safe(&instance->free_objs_list, p, pnext, list) { list_del(&p->list); free(p); lisp_debug(instance, "freed (all) cons %p", p); @@ -296,11 +292,9 @@ static void free_objects(struct alisp_instance *instance)
static struct alisp_object * search_object_identifier(struct alisp_instance *instance, const char *s) { - struct list_head * pos; struct alisp_object * p;
- list_for_each(pos, &instance->used_objs_list[get_string_hash(s)][ALISP_OBJ_IDENTIFIER]) { - p = list_entry(pos, struct alisp_object, list); + list_for_each(&instance->used_objs_list[get_string_hash(s)][ALISP_OBJ_IDENTIFIER], p, list) { if (alisp_get_refs(p) > ALISP_MAX_REFS_LIMIT) continue; if (!strcmp(p->value.s, s)) @@ -312,11 +306,9 @@ static struct alisp_object * search_object_identifier(struct alisp_instance *ins
static struct alisp_object * search_object_string(struct alisp_instance *instance, const char *s) { - struct list_head * pos; struct alisp_object * p;
- list_for_each(pos, &instance->used_objs_list[get_string_hash(s)][ALISP_OBJ_STRING]) { - p = list_entry(pos, struct alisp_object, list); + list_for_each(&instance->used_objs_list[get_string_hash(s)][ALISP_OBJ_STRING], p, list) { if (!strcmp(p->value.s, s)) { if (alisp_get_refs(p) > ALISP_MAX_REFS_LIMIT) continue; @@ -329,11 +321,9 @@ static struct alisp_object * search_object_string(struct alisp_instance *instanc
static struct alisp_object * search_object_integer(struct alisp_instance *instance, long in) { - struct list_head * pos; struct alisp_object * p;
- list_for_each(pos, &instance->used_objs_list[in & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_INTEGER]) { - p = list_entry(pos, struct alisp_object, list); + list_for_each(&instance->used_objs_list[in & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_INTEGER], p, list) { if (p->value.i == in) { if (alisp_get_refs(p) > ALISP_MAX_REFS_LIMIT) continue; @@ -346,11 +336,9 @@ static struct alisp_object * search_object_integer(struct alisp_instance *instan
static struct alisp_object * search_object_float(struct alisp_instance *instance, double in) { - struct list_head * pos; struct alisp_object * p;
- list_for_each(pos, &instance->used_objs_list[(long)in & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_FLOAT]) { - p = list_entry(pos, struct alisp_object, list); + list_for_each(&instance->used_objs_list[(long)in & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_FLOAT], p, list) { if (p->value.i == in) { if (alisp_get_refs(p) > ALISP_MAX_REFS_LIMIT) continue; @@ -363,11 +351,9 @@ static struct alisp_object * search_object_float(struct alisp_instance *instance
static struct alisp_object * search_object_pointer(struct alisp_instance *instance, const void *ptr) { - struct list_head * pos; struct alisp_object * p;
- list_for_each(pos, &instance->used_objs_list[(long)ptr & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_POINTER]) { - p = list_entry(pos, struct alisp_object, list); + list_for_each(&instance->used_objs_list[(long)ptr & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_POINTER], p, list) { if (p->value.ptr == ptr) { if (alisp_get_refs(p) > ALISP_MAX_REFS_LIMIT) continue; @@ -866,7 +852,6 @@ static int check_set_object(struct alisp_instance * instance, struct alisp_objec
static struct alisp_object_pair * set_object(struct alisp_instance *instance, struct alisp_object * name, struct alisp_object * value) { - struct list_head *pos; struct alisp_object_pair *p; const char *id;
@@ -875,8 +860,7 @@ static struct alisp_object_pair * set_object(struct alisp_instance *instance, st
id = name->value.s;
- list_for_each(pos, &instance->setobjs_list[get_string_hash(id)]) { - p = list_entry(pos, struct alisp_object_pair, list); + list_for_each(&instance->setobjs_list[get_string_hash(id)], p, list) { if (!strcmp(p->name, id)) { delete_tree(instance, p->value); p->value = value; @@ -902,7 +886,6 @@ static struct alisp_object_pair * set_object(struct alisp_instance *instance, st
static struct alisp_object * unset_object(struct alisp_instance *instance, struct alisp_object * name) { - struct list_head *pos; struct alisp_object *res; struct alisp_object_pair *p; const char *id; @@ -914,8 +897,7 @@ static struct alisp_object * unset_object(struct alisp_instance *instance, struc } id = name->value.s;
- list_for_each(pos, &instance->setobjs_list[get_string_hash(id)]) { - p = list_entry(pos, struct alisp_object_pair, list); + list_for_each(&instance->setobjs_list[get_string_hash(id)], p, list) { if (!strcmp(p->name, id)) { list_del(&p->list); res = p->value; @@ -931,10 +913,8 @@ static struct alisp_object * unset_object(struct alisp_instance *instance, struc static struct alisp_object * get_object1(struct alisp_instance *instance, const char *id) { struct alisp_object_pair *p; - struct list_head *pos;
- list_for_each(pos, &instance->setobjs_list[get_string_hash(id)]) { - p = list_entry(pos, struct alisp_object_pair, list); + list_for_each(&instance->setobjs_list[get_string_hash(id)], p, list) { if (!strcmp(p->name, id)) return p->value; } @@ -956,7 +936,6 @@ static struct alisp_object * replace_object(struct alisp_instance *instance, str { struct alisp_object_pair *p; struct alisp_object *r; - struct list_head *pos; const char *id;
if (!alisp_compare_type(name, ALISP_OBJ_IDENTIFIER) && @@ -965,8 +944,7 @@ static struct alisp_object * replace_object(struct alisp_instance *instance, str return &alsa_lisp_nil; } id = name->value.s; - list_for_each(pos, &instance->setobjs_list[get_string_hash(id)]) { - p = list_entry(pos, struct alisp_object_pair, list); + list_for_each(&instance->setobjs_list[get_string_hash(id)], p, list) { if (!strcmp(p->name, id)) { r = p->value; p->value = onew; @@ -981,7 +959,6 @@ static void dump_objects(struct alisp_instance *instance, const char *fname) { struct alisp_object_pair *p; snd_output_t *out; - struct list_head *pos; int i, err;
if (!strcmp(fname, "-")) @@ -994,8 +971,7 @@ static void dump_objects(struct alisp_instance *instance, const char *fname) }
for (i = 0; i < ALISP_OBJ_PAIR_HASH_SIZE; i++) { - list_for_each(pos, &instance->setobjs_list[i]) { - p = list_entry(pos, struct alisp_object_pair, list); + list_for_each(&instance->setobjs_list[i], p, list) { if (alisp_compare_type(p->value, ALISP_OBJ_CONS) && alisp_compare_type(p->value->value.c.car, ALISP_OBJ_IDENTIFIER) && !strcmp(p->value->value.c.car->value.s, "lambda")) { @@ -1029,15 +1005,13 @@ static const char *obj_type_str(struct alisp_object * p)
static void print_obj_lists(struct alisp_instance *instance, snd_output_t *out) { - struct list_head *pos; struct alisp_object * p; int i, j;
snd_output_printf(out, "** used objects\n"); for (i = 0; i < ALISP_OBJ_PAIR_HASH_SIZE; i++) for (j = 0; j <= ALISP_OBJ_LAST_SEARCH; j++) - list_for_each(pos, &instance->used_objs_list[i][j]) { - p = list_entry(pos, struct alisp_object, list); + list_for_each(&instance->used_objs_list[i][j], p, list) { snd_output_printf(out, "** %p (%s) (", p, obj_type_str(p)); if (!alisp_compare_type(p, ALISP_OBJ_CONS)) princ_object(out, p); @@ -1046,8 +1020,7 @@ static void print_obj_lists(struct alisp_instance *instance, snd_output_t *out) snd_output_printf(out, ") refs=%i\n", alisp_get_refs(p)); } snd_output_printf(out, "** free objects\n"); - list_for_each(pos, &instance->free_objs_list) { - p = list_entry(pos, struct alisp_object, list); + list_for_each(&instance->free_objs_list, p, list) { snd_output_printf(out, "** %p\n", p); } } diff --git a/src/async.c b/src/async.c index 98aec78..fbe2ad1 100644 --- a/src/async.c +++ b/src/async.c @@ -52,11 +52,10 @@ static LIST_HEAD(snd_async_handlers); static void snd_async_handler(int signo ATTRIBUTE_UNUSED, siginfo_t *siginfo, void *context ATTRIBUTE_UNUSED) { int fd; - struct list_head *i; + snd_async_handler_t *h; //assert(siginfo->si_code == SI_SIGIO); fd = siginfo->si_fd; - list_for_each(i, &snd_async_handlers) { - snd_async_handler_t *h = list_entry(i, snd_async_handler_t, glist); + list_for_each(&snd_async_handlers, h, glist) { if (h->fd == fd && h->callback) h->callback(h); } diff --git a/src/control/control.c b/src/control/control.c index 4a28cf6..766fc49 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -90,7 +90,7 @@ int snd_ctl_close(snd_ctl_t *ctl) { int err; while (!list_empty(&ctl->async_handlers)) { - snd_async_handler_t *h = list_entry(&ctl->async_handlers.next, snd_async_handler_t, hlist); + snd_async_handler_t *h = list_entry(ctl->async_handlers.next, snd_async_handler_t, hlist); snd_async_del_handler(h); } err = ctl->ops->close(ctl); diff --git a/src/control/setup.c b/src/control/setup.c index f23bf2c..14b933a 100644 --- a/src/control/setup.c +++ b/src/control/setup.c @@ -82,12 +82,11 @@ static int free_elems(snd_sctl_t *h) */ int snd_sctl_install(snd_sctl_t *h) { - struct list_head *pos; + snd_sctl_elem_t *elem; int err; unsigned int k; assert(h); - list_for_each(pos, &h->elems) { - snd_sctl_elem_t *elem = list_entry(pos, snd_sctl_elem_t, list); + list_for_each(&h->elems, elem, list) { unsigned int count; snd_ctl_elem_type_t type; if (elem->lock) { @@ -180,11 +179,10 @@ int snd_sctl_install(snd_sctl_t *h) */ int snd_sctl_remove(snd_sctl_t *h) { - struct list_head *pos; + snd_sctl_elem_t *elem; int err; assert(h); - list_for_each(pos, &h->elems) { - snd_sctl_elem_t *elem = list_entry(pos, snd_sctl_elem_t, list); + list_for_each(&h->elems, elem, list) { if (elem->lock) { err = snd_ctl_elem_unlock(h->ctl, elem->id); if (err < 0) { diff --git a/src/dlmisc.c b/src/dlmisc.c index b36c48f..bb6b99f 100644 --- a/src/dlmisc.c +++ b/src/dlmisc.c @@ -226,13 +226,11 @@ static LIST_HEAD(pcm_dlobj_list); void *snd_dlobj_cache_get(const char *lib, const char *name, const char *version, int verbose) { - struct list_head *p; struct dlobj_cache *c; void *func, *dlobj;
snd_dlobj_lock(); - list_for_each(p, &pcm_dlobj_list) { - c = list_entry(p, struct dlobj_cache, list); + list_for_each(&pcm_dlobj_list, c, list) { if (c->lib && lib && strcmp(c->lib, lib) != 0) continue; if (!c->lib && lib) @@ -287,7 +285,6 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
int snd_dlobj_cache_put(void *func) { - struct list_head *p; struct dlobj_cache *c; unsigned int refcnt;
@@ -295,8 +292,7 @@ int snd_dlobj_cache_put(void *func) return -ENOENT;
snd_dlobj_lock(); - list_for_each(p, &pcm_dlobj_list) { - c = list_entry(p, struct dlobj_cache, list); + list_for_each(&pcm_dlobj_list, c, list) { if (c->func == func) { refcnt = c->refcnt; if (c->refcnt > 0) @@ -311,15 +307,13 @@ int snd_dlobj_cache_put(void *func)
void snd_dlobj_cache_cleanup(void) { - struct list_head *p, *npos; - struct dlobj_cache *c; + struct dlobj_cache *c, *nc;
snd_dlobj_lock(); - list_for_each_safe(p, npos, &pcm_dlobj_list) { - c = list_entry(p, struct dlobj_cache, list); + list_for_each_safe(&pcm_dlobj_list, c, nc, list) { if (c->refcnt) continue; - list_del(p); + list_del(&c->list); snd_dlclose(c->dlobj); free((void *)c->name); /* shut up gcc warning */ free((void *)c->lib); /* shut up gcc warning */ diff --git a/src/mixer/bag.c b/src/mixer/bag.c index d88a900..576bd31 100644 --- a/src/mixer/bag.c +++ b/src/mixer/bag.c @@ -54,9 +54,8 @@ int bag_add(bag_t *bag, void *ptr)
int bag_del(bag_t *bag, void *ptr) { - struct list_head *pos; - list_for_each(pos, bag) { - bag1_t *b = list_entry(pos, bag1_t, list); + bag1_t *b; + list_for_each(bag, b, list) { if (b->ptr == ptr) { list_del(&b->list); free(b); diff --git a/src/mixer/mixer.c b/src/mixer/mixer.c index 3a79c8e..025be1a 100644 --- a/src/mixer/mixer.c +++ b/src/mixer/mixer.c @@ -170,16 +170,14 @@ static int hctl_event_handler(snd_hctl_t *hctl, unsigned int mask, snd_mixer_t *mixer = snd_hctl_get_callback_private(hctl); int res = 0; if (mask & SND_CTL_EVENT_MASK_ADD) { - struct list_head *pos; + snd_mixer_class_t *c; bag_t *bag; int err = bag_new(&bag); if (err < 0) return err; snd_hctl_elem_set_callback(elem, hctl_elem_event_handler); snd_hctl_elem_set_callback_private(elem, bag); - list_for_each(pos, &mixer->classes) { - snd_mixer_class_t *c; - c = list_entry(pos, snd_mixer_class_t, list); + list_for_each(&mixer->classes, c, list) { err = c->event(c, mask, elem, NULL); if (err < 0) res = err; @@ -249,13 +247,11 @@ int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl) */ int snd_mixer_detach(snd_mixer_t *mixer, const char *name) { - struct list_head *pos; - list_for_each(pos, &mixer->slaves) { - snd_mixer_slave_t *s; - s = list_entry(pos, snd_mixer_slave_t, list); + snd_mixer_slave_t *s; + list_for_each(&mixer->slaves, s, list) { if (strcmp(name, snd_hctl_name(s->hctl)) == 0) { snd_hctl_close(s->hctl); - list_del(pos); + list_del(&s->list); free(s); return 0; } @@ -273,12 +269,10 @@ int snd_mixer_detach(snd_mixer_t *mixer, const char *name) */ int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl) { - struct list_head *pos; - list_for_each(pos, &mixer->slaves) { - snd_mixer_slave_t *s; - s = list_entry(pos, snd_mixer_slave_t, list); + snd_mixer_slave_t *s; + list_for_each(&mixer->slaves, s, list) { if (hctl == s->hctl) { - list_del(pos); + list_del(&s->list); free(s); return 0; } @@ -295,10 +289,8 @@ int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl) */ int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl) { - struct list_head *pos; - list_for_each(pos, &mixer->slaves) { - snd_mixer_slave_t *s; - s = list_entry(pos, snd_mixer_slave_t, list); + snd_mixer_slave_t *s; + list_for_each(&mixer->slaves, s, list) { if (strcmp(name, snd_hctl_name(s->hctl)) == 0) { *hctl = s->hctl; return 0; @@ -515,16 +507,14 @@ int snd_mixer_elem_value(snd_mixer_elem_t *elem) */ int snd_mixer_class_register(snd_mixer_class_t *class, snd_mixer_t *mixer) { - struct list_head *pos; + snd_mixer_slave_t *slave; class->mixer = mixer; list_add_tail(&class->list, &mixer->classes); if (!class->event) return 0; - list_for_each(pos, &mixer->slaves) { + list_for_each(&mixer->slaves, slave, list) { int err; - snd_mixer_slave_t *slave; snd_hctl_elem_t *elem; - slave = list_entry(pos, snd_mixer_slave_t, list); elem = snd_hctl_first_elem(slave->hctl); while (elem) { err = class->event(class, SND_CTL_EVENT_MASK_ADD, elem, NULL); @@ -567,11 +557,9 @@ int snd_mixer_class_unregister(snd_mixer_class_t *class) */ int snd_mixer_load(snd_mixer_t *mixer) { - struct list_head *pos; - list_for_each(pos, &mixer->slaves) { + snd_mixer_slave_t *s; + list_for_each(&mixer->slaves, s, list) { int err; - snd_mixer_slave_t *s; - s = list_entry(pos, snd_mixer_slave_t, list); err = snd_hctl_load(s->hctl); if (err < 0) return err; @@ -585,10 +573,8 @@ int snd_mixer_load(snd_mixer_t *mixer) */ void snd_mixer_free(snd_mixer_t *mixer) { - struct list_head *pos; - list_for_each(pos, &mixer->slaves) { - snd_mixer_slave_t *s; - s = list_entry(pos, snd_mixer_slave_t, list); + snd_mixer_slave_t *s; + list_for_each(&mixer->slaves, s, list) { snd_hctl_free(s->hctl); } } @@ -685,13 +671,11 @@ int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t compare) */ int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer) { - struct list_head *pos; + snd_mixer_slave_t *s; unsigned int c = 0; assert(mixer); - list_for_each(pos, &mixer->slaves) { - snd_mixer_slave_t *s; + list_for_each(&mixer->slaves, s, list) { int n; - s = list_entry(pos, snd_mixer_slave_t, list); n = snd_hctl_poll_descriptors_count(s->hctl); if (n < 0) return n; @@ -709,13 +693,11 @@ int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer) */ int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space) { - struct list_head *pos; + snd_mixer_slave_t *s; unsigned int count = 0; assert(mixer); - list_for_each(pos, &mixer->slaves) { - snd_mixer_slave_t *s; + list_for_each(&mixer->slaves, s, list) { int n; - s = list_entry(pos, snd_mixer_slave_t, list); n = snd_hctl_poll_descriptors(s->hctl, pfds, space); if (n < 0) return n; @@ -839,13 +821,11 @@ snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem) */ int snd_mixer_handle_events(snd_mixer_t *mixer) { - struct list_head *pos; + snd_mixer_slave_t *s; assert(mixer); mixer->events = 0; - list_for_each(pos, &mixer->slaves) { + list_for_each(&mixer->slaves, s, list) { int err; - snd_mixer_slave_t *s; - s = list_entry(pos, snd_mixer_slave_t, list); err = snd_hctl_handle_events(s->hctl); if (err < 0) return err; diff --git a/src/mixer/mixer_local.h b/src/mixer/mixer_local.h index 27b4a3b..6d307d4 100644 --- a/src/mixer/mixer_local.h +++ b/src/mixer/mixer_local.h @@ -39,8 +39,8 @@ void bag_del_all(bag_t *bag); typedef struct list_head *bag_iterator_t;
#define bag_iterator_entry(i) (list_entry((i), bag1_t, list)->ptr) -#define bag_for_each(pos, bag) list_for_each(pos, bag) -#define bag_for_each_safe(pos, next, bag) list_for_each_safe(pos, next, bag) +#define bag_for_each(pos, bag) list_for_each_raw(bag, pos) +#define bag_for_each_safe(pos, next, bag) list_for_each_raw_safe(bag, pos, next)
struct _snd_mixer_class { struct list_head list; diff --git a/src/mixer/simple.c b/src/mixer/simple.c index fd9ba93..af9118d 100644 --- a/src/mixer/simple.c +++ b/src/mixer/simple.c @@ -133,12 +133,10 @@ int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t * snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer, const snd_mixer_selem_id_t *id) { - struct list_head *list; snd_mixer_elem_t *e; sm_selem_t *s;
- list_for_each(list, &mixer->elems) { - e = list_entry(list, snd_mixer_elem_t, list); + list_for_each(&mixer->elems, e, list) { if (e->type != SND_MIXER_ELEM_SIMPLE) continue; s = e->private_data; diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c index ce1cf36..aa44cfd 100644 --- a/src/pcm/pcm_hooks.c +++ b/src/pcm/pcm_hooks.c @@ -79,12 +79,11 @@ static void hook_remove_dlobj(struct snd_pcm_hook_dllist *dl) static int snd_pcm_hooks_close(snd_pcm_t *pcm) { snd_pcm_hooks_t *h = pcm->private_data; - struct list_head *pos, *next; + snd_pcm_hook_t *hook, *nhook; unsigned int k; int res = 0, err;
- list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_CLOSE]) { - snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list); + list_for_each_safe(&h->hooks[SND_PCM_HOOK_TYPE_CLOSE], hook, nhook, list) { err = hook->func(hook); if (err < 0) res = err; @@ -93,14 +92,13 @@ static int snd_pcm_hooks_close(snd_pcm_t *pcm) struct list_head *hooks = &h->hooks[k]; while (!list_empty(hooks)) { snd_pcm_hook_t *hook; - pos = hooks->next; - hook = list_entry(pos, snd_pcm_hook_t, list); + hook = list_entry(hooks->next, snd_pcm_hook_t, list); snd_pcm_hook_remove(hook); } } while (!list_empty(&h->dllist)) { - pos = h->dllist.next; - hook_remove_dlobj(list_entry(pos, struct snd_pcm_hook_dllist, list)); + hook_remove_dlobj(list_entry(h->dllist.next, struct snd_pcm_hook_dllist, + list)); } err = snd_pcm_generic_close(pcm); if (err < 0) @@ -111,12 +109,11 @@ static int snd_pcm_hooks_close(snd_pcm_t *pcm) static int snd_pcm_hooks_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { snd_pcm_hooks_t *h = pcm->private_data; - struct list_head *pos, *next; + snd_pcm_hook_t *hook, *nhook; int err = snd_pcm_generic_hw_params(pcm, params); if (err < 0) return err; - list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_HW_PARAMS]) { - snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list); + list_for_each_safe(&h->hooks[SND_PCM_HOOK_TYPE_HW_PARAMS], hook, nhook, list) { err = hook->func(hook); if (err < 0) return err; @@ -127,12 +124,11 @@ static int snd_pcm_hooks_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) static int snd_pcm_hooks_hw_free(snd_pcm_t *pcm) { snd_pcm_hooks_t *h = pcm->private_data; - struct list_head *pos, *next; + snd_pcm_hook_t *hook, *nhook; int err = snd_pcm_generic_hw_free(pcm); if (err < 0) return err; - list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_HW_FREE]) { - snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list); + list_for_each_safe(&h->hooks[SND_PCM_HOOK_TYPE_HW_FREE], hook, nhook, list) { err = hook->func(hook); if (err < 0) return err; diff --git a/src/pcm/pcm_ladspa.c b/src/pcm/pcm_ladspa.c index 631ee0f..02b904d 100644 --- a/src/pcm/pcm_ladspa.c +++ b/src/pcm/pcm_ladspa.c @@ -318,14 +318,14 @@ static void snd_pcm_ladspa_free_eps(snd_pcm_ladspa_eps_t *eps)
static void snd_pcm_ladspa_free_instances(snd_pcm_t *pcm, snd_pcm_ladspa_t *ladspa, int cleanup) { - struct list_head *list, *pos, *pos1, *next1; + struct list_head *list; + snd_pcm_ladspa_plugin_t *plugin; unsigned int idx; list = pcm->stream == SND_PCM_STREAM_PLAYBACK ? &ladspa->pplugins : &ladspa->cplugins; - list_for_each(pos, list) { - snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); - list_for_each_safe(pos1, next1, &plugin->instances) { - snd_pcm_ladspa_instance_t *instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); + list_for_each(list, plugin, list) { + snd_pcm_ladspa_instance_t *instance, *ninstance; + list_for_each_safe(&plugin->instances, instance, ninstance, list) { if (plugin->desc->deactivate) plugin->desc->deactivate(instance->handle); if (cleanup) { @@ -614,6 +614,7 @@ static int snd_pcm_ladspa_allocate_instances(snd_pcm_t *pcm, snd_pcm_ladspa_t *l unsigned int depth, idx, count; unsigned int in_channels; unsigned int in_ports, out_ports; + snd_pcm_ladspa_plugin_t *plugin; snd_pcm_ladspa_instance_t *instance = NULL; int err; @@ -621,8 +622,7 @@ static int snd_pcm_ladspa_allocate_instances(snd_pcm_t *pcm, snd_pcm_ladspa_t *l in_channels = ladspa->channels > 0 ? ladspa->channels : (pcm->stream == SND_PCM_STREAM_PLAYBACK ? pcm->channels : ladspa->plug.gen.slave->channels); depth = 0; - list_for_each(pos, list) { - snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); + list_for_each(list, plugin, list) { in_ports = snd_pcm_ladspa_count_ports(plugin, LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO); out_ports = snd_pcm_ladspa_count_ports(plugin, LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO); count = 1; @@ -685,7 +685,8 @@ static LADSPA_Data *snd_pcm_ladspa_allocate_zero(snd_pcm_ladspa_t *ladspa, unsig
static int snd_pcm_ladspa_allocate_memory(snd_pcm_t *pcm, snd_pcm_ladspa_t *ladspa) { - struct list_head *list, *pos, *pos1; + struct list_head *list; + snd_pcm_ladspa_plugin_t *plugin; snd_pcm_ladspa_instance_t *instance; unsigned int channels = 16, nchannels; unsigned int ichannels, ochannels; @@ -706,10 +707,8 @@ static int snd_pcm_ladspa_allocate_memory(snd_pcm_t *pcm, snd_pcm_ladspa_t *lads if (pchannels == NULL) return -ENOMEM; list = pcm->stream == SND_PCM_STREAM_PLAYBACK ? &ladspa->pplugins : &ladspa->cplugins; - list_for_each(pos, list) { - snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); - list_for_each(pos1, &plugin->instances) { - instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); + list_for_each(list, plugin, list) { + list_for_each(&plugin->instances, instance, list) { nchannels = channels; for (idx = 0; idx < instance->input.channels.size; idx++) { chn = instance->input.channels.array[idx]; @@ -780,10 +779,8 @@ static int snd_pcm_ladspa_allocate_memory(snd_pcm_t *pcm, snd_pcm_ladspa_t *lads /* next loop deallocates the last output LADSPA areas and connects */ /* them to ALSA areas (NULL) or dummy area ladpsa->free[1] ; */ /* this algorithm might be optimized to not allocate the last LADSPA outputs */ - list_for_each(pos, list) { - snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); - list_for_each(pos1, &plugin->instances) { - instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); + list_for_each(list, plugin, list) { + list_for_each(&plugin->instances, instance, list) { for (idx = 0; idx < instance->output.channels.size; idx++) { chn = instance->output.channels.array[idx]; if (instance->output.data[idx] == pchannels[chn]) { @@ -805,10 +802,8 @@ static int snd_pcm_ladspa_allocate_memory(snd_pcm_t *pcm, snd_pcm_ladspa_t *lads #if 0 printf("zero[0] = %p\n", ladspa->zero[0]); printf("zero[1] = %p\n", ladspa->zero[1]); - list_for_each(pos, list) { - snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); - list_for_each(pos1, &plugin->instances) { - instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); + list_for_each(list, plugin, list) { + list_for_each(&plugin->instances, instance, list) { for (idx = 0; idx < instance->input.channels.size; idx++) printf("%i:alloc-input%i: data = %p, m_data = %p\n", instance->depth, idx, instance->input.data[idx], instance->input.m_data[idx]); for (idx = 0; idx < instance->output.channels.size; idx++) @@ -857,8 +852,8 @@ snd_pcm_ladspa_write_areas(snd_pcm_t *pcm, snd_pcm_uframes_t *slave_sizep) { snd_pcm_ladspa_t *ladspa = pcm->private_data; + snd_pcm_ladspa_plugin_t *plugin; snd_pcm_ladspa_instance_t *instance; - struct list_head *pos, *pos1; LADSPA_Data *data; unsigned int idx, chn, size1, size2; @@ -874,11 +869,9 @@ snd_pcm_ladspa_write_areas(snd_pcm_t *pcm, size1 = size; if (size1 > ladspa->allocated) size1 = ladspa->allocated; - list_for_each(pos, &ladspa->pplugins) { - snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); - list_for_each(pos1, &plugin->instances) { - instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); - for (idx = 0; idx < instance->input.channels.size; idx++) { + list_for_each(&ladspa->pplugins, plugin, list) { + list_for_each(&plugin->instances, instance, list) { + for (idx = 0; idx < instance->input.channels.size; idx++) { chn = instance->input.channels.array[idx]; data = instance->input.data[idx]; if (data == NULL) { @@ -918,8 +911,8 @@ snd_pcm_ladspa_read_areas(snd_pcm_t *pcm, snd_pcm_uframes_t *slave_sizep) { snd_pcm_ladspa_t *ladspa = pcm->private_data; + snd_pcm_ladspa_plugin_t *plugin; snd_pcm_ladspa_instance_t *instance; - struct list_head *pos, *pos1; LADSPA_Data *data; unsigned int idx, chn, size1, size2;;
@@ -935,11 +928,9 @@ snd_pcm_ladspa_read_areas(snd_pcm_t *pcm, size1 = size; if (size1 > ladspa->allocated) size1 = ladspa->allocated; - list_for_each(pos, &ladspa->cplugins) { - snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); - list_for_each(pos1, &plugin->instances) { - instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); - for (idx = 0; idx < instance->input.channels.size; idx++) { + list_for_each(&ladspa->cplugins, plugin, list) { + list_for_each(&plugin->instances, instance, list) { + for (idx = 0; idx < instance->input.channels.size; idx++) { chn = instance->input.channels.array[idx]; data = instance->input.data[idx]; if (data == NULL) { @@ -1020,18 +1011,17 @@ static void snd_pcm_ladspa_dump_array(snd_output_t *out,
static void snd_pcm_ladspa_plugins_dump(struct list_head *list, snd_output_t *out) { - struct list_head *pos, *pos2; + snd_pcm_ladspa_plugin_t *plugin; - list_for_each(pos, list) { - snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); + list_for_each(list, plugin, list) { + snd_pcm_ladspa_instance_t *in; snd_output_printf(out, " Policy: %s\n", plugin->policy == SND_PCM_LADSPA_POLICY_NONE ? "none" : "duplicate"); snd_output_printf(out, " Filename: %s\n", plugin->filename); snd_output_printf(out, " Plugin Name: %s\n", plugin->desc->Name); snd_output_printf(out, " Plugin Label: %s\n", plugin->desc->Label); snd_output_printf(out, " Plugin Unique ID: %lu\n", plugin->desc->UniqueID); snd_output_printf(out, " Instances:\n"); - list_for_each(pos2, &plugin->instances) { - snd_pcm_ladspa_instance_t *in = (snd_pcm_ladspa_instance_t *) pos2; + list_for_each(&plugin->instances, in, list) { snd_output_printf(out, " Depth: %i\n", in->depth); snd_output_printf(out, " InChannels: "); snd_pcm_ladspa_dump_array(out, &in->input.channels, NULL); diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index 034f582..39bc67d 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -186,11 +186,9 @@ static void *snd_pcm_meter_thread(void *data) snd_pcm_t *pcm = data; snd_pcm_meter_t *meter = pcm->private_data; snd_pcm_t *spcm = meter->gen.slave; - struct list_head *pos; snd_pcm_scope_t *scope; int reset; - list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_scope_t, list); + list_for_each(&meter->scopes, scope, list) { snd_pcm_scope_enable(scope); } while (!meter->closed) { @@ -204,8 +202,7 @@ static void *snd_pcm_meter_thread(void *data) (status.state != SND_PCM_STATE_DRAINING || spcm->stream != SND_PCM_STREAM_PLAYBACK)) { if (meter->running) { - list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_scope_t, list); + list_for_each(&meter->scopes, scope, list) { scope->ops->stop(scope); } meter->running = 0; @@ -236,30 +233,26 @@ static void *snd_pcm_meter_thread(void *data) } } if (reset) { - list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_scope_t, list); + list_for_each(&meter->scopes, scope, list) { if (scope->enabled) scope->ops->reset(scope); } continue; } if (!meter->running) { - list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_scope_t, list); + list_for_each(&meter->scopes, scope, list) { if (scope->enabled) scope->ops->start(scope); } meter->running = 1; } - list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_scope_t, list); + list_for_each(&meter->scopes, scope, list) { if (scope->enabled) scope->ops->update(scope); } nanosleep(&meter->delay, NULL); } - list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_scope_t, list); + list_for_each(&meter->scopes, scope, list) { if (scope->enabled) snd_pcm_scope_disable(scope); } @@ -269,16 +262,14 @@ static void *snd_pcm_meter_thread(void *data) static int snd_pcm_meter_close(snd_pcm_t *pcm) { snd_pcm_meter_t *meter = pcm->private_data; - struct list_head *pos, *npos; + snd_pcm_scope_t *scope, *nscope; int err = 0; pthread_mutex_destroy(&meter->update_mutex); pthread_mutex_destroy(&meter->running_mutex); pthread_cond_destroy(&meter->running_cond); if (meter->gen.close_slave) err = snd_pcm_close(meter->gen.slave); - list_for_each_safe(pos, npos, &meter->scopes) { - snd_pcm_scope_t *scope; - scope = list_entry(pos, snd_pcm_scope_t, list); + list_for_each_safe(&meter->scopes, scope, nscope, list) { snd_pcm_scope_remove(scope); } if (meter->dl_handle) @@ -860,12 +851,10 @@ int snd_pcm_meter_add_scope(snd_pcm_t *pcm, snd_pcm_scope_t *scope) snd_pcm_scope_t *snd_pcm_meter_search_scope(snd_pcm_t *pcm, const char *name) { snd_pcm_meter_t *meter; - struct list_head *pos; + snd_pcm_scope_t *scope; assert(pcm->type == SND_PCM_TYPE_METER); meter = pcm->private_data; - list_for_each(pos, &meter->scopes) { - snd_pcm_scope_t *scope; - scope = list_entry(pos, snd_pcm_scope_t, list); + list_for_each(&meter->scopes, scope, list) { if (scope->name && strcmp(scope->name, name) == 0) return scope; } diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index 4b68f1f..27c3280 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -137,7 +137,7 @@ static snd_pcm_uframes_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave) /* Return number of frames to mmap_commit the slave */ static snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave) { - struct list_head *i; + snd_pcm_share_t *share; snd_pcm_uframes_t buffer_size; snd_pcm_sframes_t frames, safety_frames; snd_pcm_sframes_t min_frames, max_frames; @@ -147,8 +147,7 @@ static snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *sla buffer_size = slave->pcm->buffer_size; min_frames = slave_avail; max_frames = 0; - list_for_each(i, &slave->clients) { - snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list); + list_for_each(&slave->clients, share, list) { snd_pcm_t *pcm = share->pcm; switch (share->state) { case SND_PCM_STATE_RUNNING: @@ -338,11 +337,10 @@ static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm) static snd_pcm_uframes_t _snd_pcm_share_slave_missing(snd_pcm_share_slave_t *slave) { snd_pcm_uframes_t missing = INT_MAX; - struct list_head *i; + snd_pcm_share_t *share; /* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(slave->pcm); slave->hw_ptr = *slave->pcm->hw.ptr; - list_for_each(i, &slave->clients) { - snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list); + list_for_each(&slave->clients, share, list) { snd_pcm_t *pcm = share->pcm; snd_pcm_uframes_t m = _snd_pcm_share_missing(pcm); if (m < missing) @@ -1376,9 +1374,9 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname, snd_pcm_stream_t stream, int mode) { snd_pcm_t *pcm; - snd_pcm_share_t *share; + snd_pcm_share_t *share, *sh; int err; - struct list_head *i; + snd_pcm_share_slave_t *s; char slave_map[32] = { 0 }; unsigned int k; snd_pcm_share_slave_t *slave = NULL; @@ -1453,8 +1451,7 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname, }
Pthread_mutex_lock(&snd_pcm_share_slaves_mutex); - list_for_each(i, &snd_pcm_share_slaves) { - snd_pcm_share_slave_t *s = list_entry(i, snd_pcm_share_slave_t, list); + list_for_each(&snd_pcm_share_slaves, s, list) { if (s->pcm->name && strcmp(s->pcm->name, sname) == 0) { slave = s; break; @@ -1502,8 +1499,7 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname, } else { Pthread_mutex_lock(&slave->mutex); Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex); - list_for_each(i, &slave->clients) { - snd_pcm_share_t *sh = list_entry(i, snd_pcm_share_t, list); + list_for_each(&slave->clients, sh, list) { for (k = 0; k < sh->channels; ++k) { if (slave_map[sh->slave_channels[k]]) { SNDERR("Slave channel %d is already in use", sh->slave_channels[k]); diff --git a/src/shmarea.c b/src/shmarea.c index 071f9f3..80e0b37 100644 --- a/src/shmarea.c +++ b/src/shmarea.c @@ -98,11 +98,9 @@ void snd_shm_area_destructor(void) __attribute__ ((destructor));
void snd_shm_area_destructor(void) { - struct list_head *pos; struct snd_shm_area *area;
- list_for_each(pos, &shm_areas) { - area = list_entry(pos, struct snd_shm_area, list); + list_for_each(&shm_areas, area, list) { shmdt(area->ptr); } } diff --git a/src/ucm/main.c b/src/ucm/main.c index 7e44603..48d6a26 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -65,7 +65,7 @@ static int list_count(struct list_head *list) struct list_head *pos; int count = 0;
- list_for_each(pos, list) { + list_for_each_raw(list, pos) { count += 1; } return count; @@ -282,14 +282,12 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr, struct list_head *value_list2, struct list_head *value_list3) { - struct list_head *pos; struct sequence_element *s; char *cdev = NULL; snd_ctl_t *ctl = NULL; int err = 0;
- list_for_each(pos, seq) { - s = list_entry(pos, struct sequence_element, list); + list_for_each(seq, s, list) { switch (s->type) { case SEQUENCE_ELEMENT_TYPE_CDEV: cdev = strdup(s->data.cdev); @@ -406,11 +404,9 @@ static void *find0(struct list_head *list, unsigned long soffset, const char *match) { - struct list_head *pos; char *ptr, *str;
- list_for_each(pos, list) { - ptr = list_entry_offset(pos, char, offset); + list_for_each_off(list, ptr, offset) { str = *((char **)(ptr + soffset)); if (strcmp(str, match) == 0) return ptr; @@ -437,7 +433,6 @@ static int get_list0(struct list_head *list, { char **res; int cnt; - struct list_head *pos; char *ptr, *str1;
cnt = alloc_str_list(list, 1, &res); @@ -446,8 +441,7 @@ static int get_list0(struct list_head *list, return cnt; } *result = (const char **)res; - list_for_each(pos, list) { - ptr = list_entry_offset(pos, char, offset); + list_for_each_off(list, ptr, offset) { str1 = *((char **)(ptr + s1offset)); if (str1 != NULL) { *res = strdup(str1); @@ -486,7 +480,6 @@ static int get_list20(struct list_head *list, { char **res; int cnt; - struct list_head *pos; char *ptr, *str1, *str2;
cnt = alloc_str_list(list, 2, &res); @@ -495,8 +488,7 @@ static int get_list20(struct list_head *list, return cnt; } *result = (const char **)res; - list_for_each(pos, list) { - ptr = list_entry_offset(pos, char, offset); + list_for_each_off(list, ptr, offset) { str1 = *((char **)(ptr + s1offset)); if (str1 != NULL) { *res = strdup(str1); @@ -547,7 +539,6 @@ static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr, { struct dev_list_node *device; struct use_case_device *adev; - struct list_head *pos, *pos1; int found_ret;
switch (dev_list->type) { @@ -562,12 +553,8 @@ static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr, break; }
- list_for_each(pos, &dev_list->list) { - device = list_entry(pos, struct dev_list_node, list); - - list_for_each(pos1, &uc_mgr->active_devices) { - adev = list_entry(pos1, struct use_case_device, - active_list); + list_for_each(&dev_list->list, device, list) { + list_for_each(&uc_mgr->active_devices, adev, active_list) { if (!strcmp(device->name, adev->name)) return found_ret; } @@ -598,11 +585,8 @@ static inline struct use_case_device * const char *device_name, int check_supported) { struct use_case_device *device; - struct list_head *pos; - - list_for_each(pos, &verb->device_list) { - device = list_entry(pos, struct use_case_device, list);
+ list_for_each(&verb->device_list, device, list) { if (strcmp(device_name, device->name)) continue;
@@ -626,11 +610,8 @@ static struct use_case_modifier * const char *modifier_name, int check_supported) { struct use_case_modifier *modifier; - struct list_head *pos; - - list_for_each(pos, &verb->modifier_list) { - modifier = list_entry(pos, struct use_case_modifier, list);
+ list_for_each(&verb->modifier_list, modifier, list) { if (strcmp(modifier->name, modifier_name)) continue;
@@ -647,10 +628,8 @@ long device_status(snd_use_case_mgr_t *uc_mgr, const char *device_name) { struct use_case_device *dev; - struct list_head *pos;
- list_for_each(pos, &uc_mgr->active_devices) { - dev = list_entry(pos, struct use_case_device, active_list); + list_for_each(&uc_mgr->active_devices, dev, active_list) { if (strcmp(dev->name, device_name) == 0) return 1; } @@ -661,10 +640,8 @@ long modifier_status(snd_use_case_mgr_t *uc_mgr, const char *modifier_name) { struct use_case_modifier *mod; - struct list_head *pos;
- list_for_each(pos, &uc_mgr->active_modifiers) { - mod = list_entry(pos, struct use_case_modifier, active_list); + list_for_each(&uc_mgr->active_modifiers, mod, active_list) { if (strcmp(mod->name, modifier_name) == 0) return 1; } @@ -854,23 +831,18 @@ int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr) */ static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr) { - struct list_head *pos, *npos; - struct use_case_modifier *modifier; - struct use_case_device *device; + struct use_case_modifier *modifier, *nmodifier; + struct use_case_device *device, *ndevice; int err;
- list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) { - modifier = list_entry(pos, struct use_case_modifier, - active_list); + list_for_each_safe(&uc_mgr->active_modifiers, modifier, nmodifier, active_list) { err = set_modifier(uc_mgr, modifier, 0); if (err < 0) uc_error("Unable to disable modifier %s", modifier->name); } INIT_LIST_HEAD(&uc_mgr->active_modifiers);
- list_for_each_safe(pos, npos, &uc_mgr->active_devices) { - device = list_entry(pos, struct use_case_device, - active_list); + list_for_each_safe(&uc_mgr->active_devices, device, ndevice, active_list) { err = set_device(uc_mgr, device, 0); if (err < 0) uc_error("Unable to disable device %s", device->name); @@ -1057,15 +1029,12 @@ static int add_values(struct list_head *list, { struct ucm_value *v; struct myvalue *val; - struct list_head *pos, *pos1; int match;
- list_for_each(pos, source) { - v = list_entry(pos, struct ucm_value, list); + list_for_each(source, v, list) { if (check_identifier(identifier, v->name)) { match = 0; - list_for_each(pos1, list) { - val = list_entry(pos1, struct myvalue, list); + list_for_each(list, val, list) { if (strcmp(val->value, v->data) == 0) { match = 1; break; @@ -1094,8 +1063,8 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr, const char **list[], char *verbname) { - struct list_head mylist, *pos, *npos; - struct myvalue *val; + struct list_head mylist; + struct myvalue *val, *nval; struct use_case_verb *verb; struct use_case_device *dev; struct use_case_modifier *mod; @@ -1116,14 +1085,12 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr, err = add_values(&mylist, identifier, &verb->value_list); if (err < 0) goto __fail; - list_for_each(pos, &verb->device_list) { - dev = list_entry(pos, struct use_case_device, list); + list_for_each(&verb->device_list, dev, list) { err = add_values(&mylist, identifier, &dev->value_list); if (err < 0) goto __fail; } - list_for_each(pos, &verb->modifier_list) { - mod = list_entry(pos, struct use_case_modifier, list); + list_for_each(&verb->modifier_list, mod, list) { err = add_values(&mylist, identifier, &mod->value_list); if (err < 0) goto __fail; @@ -1131,8 +1098,7 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr, err = alloc_str_list(&mylist, 1, &res); if (err >= 0) { *list = (const char **)res; - list_for_each(pos, &mylist) { - val = list_entry(pos, struct myvalue, list); + list_for_each(&mylist, val, list) { *res = strdup(val->value); if (*res == NULL) { snd_use_case_free_list((const char **)res, err); @@ -1143,8 +1109,7 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr, } } __fail: - list_for_each_safe(pos, npos, &mylist) { - val = list_entry(pos, struct myvalue, list); + list_for_each_safe(&mylist, val, nval, list) { list_del(&val->list); free(val); } @@ -1241,13 +1206,11 @@ static int get_value1(char **value, struct list_head *value_list, const char *identifier) { struct ucm_value *val; - struct list_head *pos;
if (!value_list) return -ENOENT;
- list_for_each(pos, value_list) { - val = list_entry(pos, struct ucm_value, list); + list_for_each(value_list, val, list) { if (check_identifier(identifier, val->name)) { *value = strdup(val->data); if (*value == NULL) @@ -1496,8 +1459,7 @@ static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr, struct transition_sequence *trans; int err;
- list_for_each(pos, &uc_mgr->active_verb->transition_list) { - trans = list_entry(pos, struct transition_sequence, list); + list_for_each(&uc_mgr->active_verb->transition_list, trans, list) { if (strcmp(trans->name, new_verb->name) == 0) { err = execute_sequence(uc_mgr, &trans->transition_list, &uc_mgr->active_verb->value_list, @@ -1585,7 +1547,6 @@ static int switch_device(snd_use_case_mgr_t *uc_mgr, { struct use_case_device *xold, *xnew; struct transition_sequence *trans; - struct list_head *pos; int err, seq_found = 0;
if (uc_mgr->active_verb == NULL) @@ -1607,8 +1568,7 @@ static int switch_device(snd_use_case_mgr_t *uc_mgr, if (xnew == NULL) return -ENOENT; err = 0; - list_for_each(pos, &xold->transition_list) { - trans = list_entry(pos, struct transition_sequence, list); + list_for_each(&xold->transition_list, trans, list) { if (strcmp(trans->name, new_device) == 0) { err = execute_sequence(uc_mgr, &trans->transition_list, &xold->value_list, @@ -1659,8 +1619,7 @@ static int switch_modifier(snd_use_case_mgr_t *uc_mgr, if (xnew == NULL) return -ENOENT; err = 0; - list_for_each(pos, &xold->transition_list) { - trans = list_entry(pos, struct transition_sequence, list); + list_for_each(&xold->transition_list, trans, list) { if (strcmp(trans->name, new_modifier) == 0) { err = execute_sequence(uc_mgr, &trans->transition_list, &xold->value_list, diff --git a/src/ucm/utils.c b/src/ucm/utils.c index 45307b0..a6a3466 100644 --- a/src/ucm/utils.c +++ b/src/ucm/utils.c @@ -87,11 +87,9 @@ int uc_mgr_config_load(const char *file, snd_config_t **cfg)
void uc_mgr_free_value(struct list_head *base) { - struct list_head *pos, *npos; - struct ucm_value *val; + struct ucm_value *val, *nval; - list_for_each_safe(pos, npos, base) { - val = list_entry(pos, struct ucm_value, list); + list_for_each_safe(base, val, nval, list) { free(val->name); free(val->data); list_del(&val->list); @@ -101,11 +99,9 @@ void uc_mgr_free_value(struct list_head *base)
void uc_mgr_free_dev_list(struct dev_list *dev_list) { - struct list_head *pos, *npos; - struct dev_list_node *dlist; + struct dev_list_node *dlist, *ndlist; - list_for_each_safe(pos, npos, &dev_list->list) { - dlist = list_entry(pos, struct dev_list_node, list); + list_for_each_safe(&dev_list->list, dlist, ndlist, list) { free(dlist->name); list_del(&dlist->list); free(dlist); @@ -129,11 +125,9 @@ void uc_mgr_free_sequence_element(struct sequence_element *seq)
void uc_mgr_free_sequence(struct list_head *base) { - struct list_head *pos, *npos; - struct sequence_element *seq; + struct sequence_element *seq, *nseq; - list_for_each_safe(pos, npos, base) { - seq = list_entry(pos, struct sequence_element, list); + list_for_each_safe(base, seq, nseq, list) { list_del(&seq->list); uc_mgr_free_sequence_element(seq); } @@ -148,11 +142,9 @@ void uc_mgr_free_transition_element(struct transition_sequence *tseq)
void uc_mgr_free_transition(struct list_head *base) { - struct list_head *pos, *npos; - struct transition_sequence *tseq; + struct transition_sequence *tseq, *ntseq; - list_for_each_safe(pos, npos, base) { - tseq = list_entry(pos, struct transition_sequence, list); + list_for_each_safe(base, tseq, ntseq, list) { list_del(&tseq->list); uc_mgr_free_transition_element(tseq); } @@ -160,11 +152,9 @@ void uc_mgr_free_transition(struct list_head *base)
void uc_mgr_free_modifier(struct list_head *base) { - struct list_head *pos, *npos; - struct use_case_modifier *mod; + struct use_case_modifier *mod, *nmod; - list_for_each_safe(pos, npos, base) { - mod = list_entry(pos, struct use_case_modifier, list); + list_for_each_safe(base, mod, nmod, list) { free(mod->name); free(mod->comment); uc_mgr_free_sequence(&mod->enable_list); @@ -179,11 +169,9 @@ void uc_mgr_free_modifier(struct list_head *base)
void uc_mgr_free_device(struct list_head *base) { - struct list_head *pos, *npos; - struct use_case_device *dev; + struct use_case_device *dev, *ndev; - list_for_each_safe(pos, npos, base) { - dev = list_entry(pos, struct use_case_device, list); + list_for_each_safe(base, dev, ndev, list) { free(dev->name); free(dev->comment); uc_mgr_free_sequence(&dev->enable_list); @@ -198,11 +186,9 @@ void uc_mgr_free_device(struct list_head *base)
void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr) { - struct list_head *pos, *npos; - struct use_case_verb *verb; + struct use_case_verb *verb, *nverb;
- list_for_each_safe(pos, npos, &uc_mgr->verb_list) { - verb = list_entry(pos, struct use_case_verb, list); + list_for_each_safe(&uc_mgr->verb_list, verb, nverb, list) { free(verb->name); free(verb->comment); uc_mgr_free_sequence(&verb->enable_list);
On Thu, 23 Jul 2015 18:02:39 +0200, Clemens Lang wrote:
Hi,
the current implementation of include/list.h is taken from Linux 2.4.0 and possibly licensed under GPL-2.0. If the implementation isn't trivial, this might make libasound a derivative work and extend the viral effect to clients of the library. See http://mailman.alsa-project.org/pipermail/alsa-devel/2014-December/085261.ht... http://mailman.alsa-project.org/pipermail/alsa-devel/2014-December/085262.ht... http://mailman.alsa-project.org/pipermail/alsa-devel/2014-December/085325.ht... http://mailman.alsa-project.org/pipermail/alsa-devel/2015-January/086754.htm... for previous discussion.
This patch series avoids this ambiguity by replacing the list implementation with a version I modified from Rusty Russell's MIT-licensed list at http://ccodearchive.net/info/list.html
The two patches replace the list implementation and adapt the alsa-lib code accordingly. They are intended to be squashed together when merging.
[PATCH 1/2] Replace list.h with MIT-licensed implementation [PATCH 2/2] Adapt to changes in the linked list API
Well, the linked-list macro is a trivial thing each beginner programmer starts writing at school. And, the API itself can't be an issue. That is, it'd be enough just rewriting the existing list.h (e.g. renaming variables, shuffles the call order, rephrase the comments) by ourselves without introducing a big piece of codes of even a different license, IMO.
Thoughts?
thanks,
Takashi
On Thu, Jul 23, 2015 at 09:03:31PM +0200, Takashi Iwai wrote:
Well, the linked-list macro is a trivial thing each beginner programmer starts writing at school. And, the API itself can't be an issue.
I agree, but that does not necessarily mean that the license wouldn't apply. Consider this thought experiment. You write a two-page prose article on how a linked list works. Obviously, the concept of a linked list is trivial -- but does that mean copyright doesn't apply to your article? I think we have a similar situation here; the concept of a list may be trivial, but that doesn't mean the implementation is.
That is, it'd be enough just rewriting the existing list.h (e.g. renaming variables, shuffles the call order, rephrase the comments) by ourselves without introducing a big piece of codes of even a different license, IMO.
Unless you re-implement a list from scratch that provides the same API that wouldn't really help you. I'm fully aware that it may not be obvious whether somebody only modified an existing file heavily or re-implemented it, but unless you start from scratch you won't free yourself from the original copyright (and thus, the license). That's also one of the reasons why I'm proposing to use a modified version of an existing implementation rather than re-writing it from scratch.
A re-implementation would also have to be tested, which the existing list already is. Additionally, I think the proposed change simplifies iterating over a list. Currently, you always need list_for_each() followed by list_entry(), which would be simplified to a single statement with this change.
On Fri, 24 Jul 2015 09:34:19 +0200, Clemens Lang wrote:
On Thu, Jul 23, 2015 at 09:03:31PM +0200, Takashi Iwai wrote:
Well, the linked-list macro is a trivial thing each beginner programmer starts writing at school. And, the API itself can't be an issue.
I agree, but that does not necessarily mean that the license wouldn't apply. Consider this thought experiment. You write a two-page prose article on how a linked list works. Obviously, the concept of a linked list is trivial -- but does that mean copyright doesn't apply to your article? I think we have a similar situation here; the concept of a list may be trivial, but that doesn't mean the implementation is.
Sure, it can be written differently. But my point is that it is (or must be) trivial to write a linked list code for C programmer. We can easily drop the existing code and replace with our own.
That is, it'd be enough just rewriting the existing list.h (e.g. renaming variables, shuffles the call order, rephrase the comments) by ourselves without introducing a big piece of codes of even a different license, IMO.
Unless you re-implement a list from scratch that provides the same API that wouldn't really help you.
So why not writing from scratch? We just need only a few things:
struct list_head list_entry() list_for_each() list_for_each_safe() list_add() list_add_tail()
I guess the definition of struct list_head will be identical in high probability if any other people write from scratch (maybe someone put next before prev). The rest are all obvious implementations. The execution order might be different, and the comments are different -- this is what I mentioned in my previous post.
I'm fully aware that it may not be obvious whether somebody only modified an existing file heavily or re-implemented it, but unless you start from scratch you won't free yourself from the original copyright (and thus, the license). That's also one of the reasons why I'm proposing to use a modified version of an existing implementation rather than re-writing it from scratch.
A re-implementation would also have to be tested, which the existing list already is. Additionally, I think the proposed change simplifies iterating over a list. Currently, you always need list_for_each() followed by list_entry(), which would be simplified to a single statement with this change.
How can you be sure that the adapted code would work with alsa-lib? You'd need to check in a similar manner no matter whether you adapt from other or you write it.
About the list_for_each(): we can replace them with list_for_each_entry(). This would be a nice cleanup.
thanks,
Takashi
On Fri, 24 Jul 2015 10:13:16 +0200, Takashi Iwai wrote:
On Fri, 24 Jul 2015 09:34:19 +0200, Clemens Lang wrote:
On Thu, Jul 23, 2015 at 09:03:31PM +0200, Takashi Iwai wrote:
Well, the linked-list macro is a trivial thing each beginner programmer starts writing at school. And, the API itself can't be an issue.
I agree, but that does not necessarily mean that the license wouldn't apply. Consider this thought experiment. You write a two-page prose article on how a linked list works. Obviously, the concept of a linked list is trivial -- but does that mean copyright doesn't apply to your article? I think we have a similar situation here; the concept of a list may be trivial, but that doesn't mean the implementation is.
Sure, it can be written differently. But my point is that it is (or must be) trivial to write a linked list code for C programmer. We can easily drop the existing code and replace with our own.
That is, it'd be enough just rewriting the existing list.h (e.g. renaming variables, shuffles the call order, rephrase the comments) by ourselves without introducing a big piece of codes of even a different license, IMO.
Unless you re-implement a list from scratch that provides the same API that wouldn't really help you.
So why not writing from scratch? We just need only a few things:
struct list_head list_entry() list_for_each() list_for_each_safe() list_add() list_add_tail()
FYI, below is an example replacement of list.h I wrote quickly from scratch. It turned out that LIST_HEAD(), INIT_LIST_HEAD(), list_del() and list_empty() are needed in addition.
Takashi
=== /* Doubly linked list macros compatible with Linux kernel */
#ifndef _LIST_H #define _LIST_H
#include <stddef.h>
struct list_head { struct list_head *next; struct list_head *prev; };
/* one-shot definition of a list head */ #define LIST_HEAD(x) \ struct list_head x = { &x, &x }
/* initialize a list head explicitly */ static inline void INIT_LIST_HEAD(struct list_head *p) { p->next = p->prev = p; }
#define list_entry_offset(p, type, offset) \ ((type *)((char *)(p) - (offset)))
/* list_entry - retrieve the original struct from list_head * @p: list_head pointer * @type: struct type * @member: struct field member containing the list_head */ #define list_entry(p, type, member) \ list_entry_offset(p, type, offsetof(type, member))
/* list_for_each - iterate over the linked list * @p: iterator, a list_head pointer variable * @list: list_head pointer containing the list */ #define list_for_each(p, list) \ for (p = (list)->next; p != (list); p = p->next)
/* list_for_each_safe - iterate over the linked list, safe to delete * @p: iterator, a list_head pointer variable * @s: a temporary variable to keep the next, a list_head pointer, too * @list: list_head pointer containing the list */ #define list_for_each_safe(p, s, list) \ for (p = (list)->next; s = p->next, p != (list); p = s)
/* list_add - prepend a list entry at the head * @p: the new list entry to add * @list: the list head */ static inline void list_add(struct list_head *p, struct list_head *list) { struct list_head *first = list->next;
p->next = first; first->prev = p; list->next = p; p->prev = list; }
/* list_add_tail - append a list entry at the tail * @p: the new list entry to add * @list: the list head */ static inline void list_add_tail(struct list_head *p, struct list_head *list) { struct list_head *last = list->prev;
last->next = p; p->prev = last; p->next = list; list->prev = p; }
/* list_del - delete the given list entry */ static inline void list_del(struct list_head *p) { p->prev->next = p->next; p->next->prev = p->prev; }
/* list_empty - returns 1 if the given list is empty */ static inline int list_empty(const struct list_head *p) { return p->next == p; }
#endif /* _LIST_H */
Hi,
On Fri, Jul 24, 2015 at 06:32:30PM +0200, Takashi Iwai wrote:
FYI, below is an example replacement of list.h I wrote quickly from scratch. It turned out that LIST_HEAD(), INIT_LIST_HEAD(), list_del() and list_empty() are needed in addition.
That looks good, thanks for the effort. Who can merge this? Should I put this into a format that can be used by git-am or will you?
Thanks, Clemens
On Mon, 27 Jul 2015 11:45:41 +0200, Clemens Lang wrote:
Hi,
On Fri, Jul 24, 2015 at 06:32:30PM +0200, Takashi Iwai wrote:
FYI, below is an example replacement of list.h I wrote quickly from scratch. It turned out that LIST_HEAD(), INIT_LIST_HEAD(), list_del() and list_empty() are needed in addition.
That looks good, thanks for the effort. Who can merge this? Should I put this into a format that can be used by git-am or will you?
I'm going to merge this properly. Thanks for checking.
Takashi
participants (3)
-
Clemens Lang
-
Jaroslav Kysela
-
Takashi Iwai