From: Mathieu Desnoyers Date: Tue, 29 Sep 2009 20:41:35 +0000 (-0400) Subject: only keep formal model X-Git-Url: http://git.liburcu.org/?p=userspace-rcu.git;a=commitdiff_plain;h=4835864e6a18488deaad4ef96c10aceb717222a1 only keep formal model --- diff --git a/LICENSE b/LICENSE deleted file mode 100644 index ad13f78..0000000 --- a/LICENSE +++ /dev/null @@ -1,59 +0,0 @@ -Userspace RCU library licensing -Mathieu Desnoyers -May 10, 2009 - - -* LGPLv2.1 - -The library part is distributed under LGPLv2.1 or later. See lgpl-2.1.txt for -details. This applies to : - -urcu.h -urcu.c -urcu-static.h -arch_x86.h -arch_ppc.h - -LGPL-compatible source code can statically use the library header using : - -#define _LGPL_SOURCE -#include - -Dynamic-only linking with the LGPL library is used if _LGPL_SOURCE is not -defined. It permits relinking with newer versions of the library, which is -required by the LGPL license. - -See lgpl-relicensing.txt for details. - - -* MIT-style license : - -xchg() primitive has been rewritten from scratch starting from atomic_ops 1.2 -which has a MIT-style license that is intended to allow use in both free and -proprietary software: - http://www.hpl.hp.com/research/linux/atomic_ops/LICENSING.txt - http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/ - -This license applies to : - -arch_atomic_x86.h -arch_atomic_ppc.h -arch_atomic_s390.h -arch_s390.h -compiler.h - - -* GPLv2 - -Library test code is distributed under the GPLv2 license. See gpl-2.0.txt for -details. This applies to : - -urcutorture.h -urcutorture.c -api_x86.h -api_ppc.h -api_gcc.h -test_urcu.c -test_urcu_yield.c -test_rwlock_timing.c -urcu-asm.c diff --git a/Makefile b/Makefile deleted file mode 100644 index ab19097..0000000 --- a/Makefile +++ /dev/null @@ -1 +0,0 @@ -include Makefile.inc diff --git a/Makefile.build.inc b/Makefile.build.inc deleted file mode 100644 index 010bcf5..0000000 --- a/Makefile.build.inc +++ /dev/null @@ -1,45 +0,0 @@ - -CFLAGS=-Wall -I. - -#optimized -CFLAGS+=-O2 - -#debug information -CFLAGS+=-g - -#RCU debug (slower, with error-checks) -#CFLAGS+=-DDEBUG_RCU - -LDFLAGS=-lpthread - -HOSTTYPE=$(shell uname -m) - -ifeq ("${HOSTTYPE}","x86_64") -ARCHTYPE=x86 -endif -ifeq ("${HOSTTYPE}","i586") -ARCHTYPE=x86 -endif -ifeq ("${HOSTTYPE}","i686") -ARCHTYPE=x86 -endif -ifeq ("${HOSTTYPE}","powerpc") -ARCHTYPE=ppc -endif -ifeq ("${HOSTTYPE}","ppc64") -ARCHTYPE=ppc -endif -ifeq ("${HOSTTYPE}","ppc") -ARCHTYPE=ppc -endif -ifeq ("${HOSTTYPE}","s390") -ARCHTYPE=s390 -endif -ifeq ("${HOSTTYPE}","s390x") -ARCHTYPE=s390 -endif - -#Changing the signal number used by the library. SIGUSR1 by default. -#CFLAGS+=-DSIGURCU=SIGUSR2 - -SRC_DEP=`echo $^ | sed 's/[^ ]*\.h//g'` diff --git a/Makefile.inc b/Makefile.inc deleted file mode 100644 index 3fc3a6c..0000000 --- a/Makefile.inc +++ /dev/null @@ -1,75 +0,0 @@ - -include Makefile.build.inc - -DIRS=tests - -all: checkarch liburcu.so urcu.o \ - liburcu-qsbr.so urcu-qsbr.o \ - liburcu-mb.so urcu-mb.o \ - liburcu-defer.so urcu-defer.o \ - urcu-yield.o \ - subdirs - -checkarch: -ifeq (${ARCHTYPE},) - @echo "Architecture ${HOSTTYPE} is currently unsupported by liburcu" - @exit 1 -endif - -urcu/arch.h: urcu/arch_${ARCHTYPE}.h - cp -f urcu/arch_${ARCHTYPE}.h urcu/arch.h - -urcu/arch_uatomic.h: urcu/arch_uatomic_${ARCHTYPE}.h - cp -f urcu/arch_uatomic_${ARCHTYPE}.h urcu/arch_uatomic.h - -urcu.h: urcu/arch.h urcu/arch_uatomic.h - -urcu-qsbr.h: urcu/arch.h urcu/arch_uatomic.h - -urcu.o: urcu.c urcu.h - $(CC) -fPIC ${CFLAGS} -c -o $@ $(SRC_DEP) - -urcu-mb.o: urcu.c urcu.h - $(CC) -fPIC -DURCU_MB ${CFLAGS} -c -o $@ $(SRC_DEP) - -urcu-qsbr.o: urcu-qsbr.c urcu-qsbr.h - $(CC) -fPIC ${CFLAGS} -c -o $@ $(SRC_DEP) - -urcu-defer.o: urcu-defer.c urcu-defer.h - $(CC) -fPIC ${CFLAGS} -c -o $@ $(SRC_DEP) - -liburcu.so: urcu.o - $(CC) ${LDFLAGS} -fPIC -shared -o $@ $< - -liburcu-qsbr.so: urcu-qsbr.o - $(CC) ${LDFLAGS} -fPIC -shared -o $@ $< - -liburcu-mb.so: urcu-mb.o - $(CC) ${LDFLAGS} -fPIC -shared -o $@ $< - -liburcu-defer.so: urcu-defer.o - $(CC) ${LDFLAGS} -fPIC -shared -o $@ $< - -urcu-yield.o: urcu.c urcu.h - $(CC) -DDEBUG_YIELD ${CFLAGS} -c -o $@ $(SRC_DEP) - -.PHONY: clean install checkarch tests - -subdirs: - -for d in ${DIRS}; do cd $${d}; ${MAKE} ${MFLAGS} ${EXTRAMFLAGS}; done - -install: liburcu.so - cp -f liburcu.so liburcu-mb.so liburcu-qsbr.so liburcu-defer.so \ - /usr/lib/ - mkdir -p /usr/include/urcu - cp -f urcu/arch.h urcu/arch_uatomic.h urcu/compiler.h \ - urcu/list.h urcu/rculist.h urcu/hlist.h \ - /usr/include/urcu/ - cp -f urcu.h urcu-static.h \ - urcu-qsbr.h urcu-qsbr-static.h \ - urcu-defer.h urcu-defer-static.h \ - /usr/include/ - -clean: - rm -f *.o *.so urcu/arch.h urcu/arch_uatomic.h - -for d in ${DIRS}; do cd $${d}; ${MAKE} clean; done diff --git a/Makefile32 b/Makefile32 deleted file mode 100644 index ab57691..0000000 --- a/Makefile32 +++ /dev/null @@ -1,5 +0,0 @@ -include Makefile.inc - -EXTRAMFLAGS=-f Makefile32 -CFLAGS+=-m32 -LDFLAGS+=-m32 diff --git a/Makefile64 b/Makefile64 deleted file mode 100644 index 83ee8da..0000000 --- a/Makefile64 +++ /dev/null @@ -1,5 +0,0 @@ -include Makefile.inc - -EXTRAMFLAGS=-f Makefile64 -CFLAGS+=-m64 -LDFLAGS+=-m64 diff --git a/README b/README deleted file mode 100644 index e5c04b1..0000000 --- a/README +++ /dev/null @@ -1,113 +0,0 @@ -Userspace RCU Implementation -by Mathieu Desnoyers and Paul E. McKenney - -BUILDING --------- - - make - #force 32-bit build with: make -f Makefile32 - #force 64-bit build with: make -f Makefile64 - make install - - -QUICK START GUIDE ------------------ - -Usage of all urcu libraries - - * Define _LGPL_SOURCE (only) if your code is LGPL or GPL compatible - before including the urcu.h or urcu-qsbr.h header. If your application - is distributed under another license, function calls will be generated - instead of inlines, so your application can link with the library. - * Linking with one of the libraries below is always necessary even for - LGPL and GPL applications. - -Usage of liburcu - - * #include - * Link the application with "-lurcu". - * This is the preferred version of the library, both in terms of speed - and flexibility. Requires a signal, typically SIGUSR1. Can be - overridden with -DSIGURCU by modifying Makefile.build.inc. - -Usage of liburcu-mb - - * #include - * Compile any _LGPL_SOURCE code using this library with "-DURCU_MB". - * Link with "-lurcu-mb". - * This version of the urcu library does not need to - reserve a signal number. URCU_MB uses full memory barriers for - readers. This eliminates the need for signals but results in slower - reads. - -Usage of liburcu-qsbr - - * #include - * Link with "-lurcu-qsbr". - * The QSBR flavor of RCU needs to have each reader thread executing - rcu_quiescent_state() periodically to progress. rcu_thread_online() - and rcu_thread_offline() can be used to mark long periods for which - the threads are not active. It provides the fastest read-side at the - expense of more intrusiveness in the application code. - -Initialization - - Each thread that has reader critical sections (that uses - rcu_read_lock()/rcu_read_unlock() must first register to the URCU - library. This is done by calling rcu_register_thread(). Unregistration - must be performed before exiting the thread by using - rcu_unregister_thread(). - -Reading - - Reader critical sections must be protected by locating them between - calls to rcu_read_lock() and rcu_read_unlock(). Inside that lock, - rcu_dereference() may be called to read an RCU protected pointer. - -Writing - - rcu_assign_pointer() and rcu_xchg_pointer() may be called anywhere. - After, synchronize_rcu() must be called. When it returns, the old - values are not in usage anymore. - -Usage of liburcu-defer - - * #include - * Link with "-lurcu-defer" - * Provides call_rcu() primitive to enqueue delayed callbacks. Queued - callbacks are executed in batch periodically after a grace period. - Do _not_ use call_rcu() within a read-side critical section, because - it may call synchronize_rcu() if the thread queue is full. - -Being careful with signals - - The liburcu library uses signals internally. The signal handler is - registered with the SA_RESTART flag. However, these signals may cause - some non-restartable system calls to fail with errno = EINTR. Care - should be taken to restart system calls manually if they fail with this - error. A list of non-restartable system calls may be found in - signal(7). The liburcu-mb and liburcu-qsbr versions of the Userspace RCU - library do not require any signal. - - Read-side critical sections are allowed in a signal handler with - liburcu and liburcu-mb. Be careful, however, to disable these signals - between thread creation and calls to rcu_register_thread(), because a - signal handler nesting on an unregistered thread would not be allowed to - call rcu_read_lock(). - - Read-side critical sections are _not_ allowed in a signal handler with - liburcu-qsbr, unless signals are disabled explicitly around each - rcu_quiescent_state() calls, when threads are put offline and around - calls to synchronize_rcu(). Even then, we do not recommend it. - -Usage of DEBUG_RCU - - DEBUG_RCU is used to add internal debugging self-checks to the - RCU library. This define adds a performance penalty when enabled. - Can be enabled by uncommenting the corresponding line in - Makefile.build.inc. - -Usage of DEBUG_YIELD - - DEBUG_YIELD is used to add random delays in the code for testing - purposes. diff --git a/gpl-2.0.txt b/gpl-2.0.txt deleted file mode 100644 index d511905..0000000 --- a/gpl-2.0.txt +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/lgpl-2.1.txt b/lgpl-2.1.txt deleted file mode 100644 index 602bfc9..0000000 --- a/lgpl-2.1.txt +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/lgpl-relicensing.txt b/lgpl-relicensing.txt deleted file mode 100644 index e3ebc59..0000000 --- a/lgpl-relicensing.txt +++ /dev/null @@ -1,29 +0,0 @@ -Mathieu Desnoyers -May 13th, 2009 - -IBM Corporation allowed LGPLv2.1+ licensing of their contribution to the -userspace RCU library in a patch submitted on May 8, 2009 from Paul E. -McKenney and reviewed by Steven L. Bennett: - - http://lists.casi.polymtl.ca/pipermail/ltt-dev/2009-May/001584.html - -I (Mathieu Desnoyers) re-implemented ACCESS_ONCE(), likely(), unlikely() and -barrier() from scratch without reference to the original code. - - commit id : 2dc5fa0f7cfbfb0a64a7a67b39626650e863f16a - -Bert Wesarg approved LGPL relicensing of his -patch in an email dated May 13, 2009 : - - http://lkml.org/lkml/2009/5/13/16 - -xchg() primitives has been rewritten from a MIT-licensed cmpxchg for Intel -and powerpc. They are MIT-licensed and therefore usable in LGPL code. -This cmpxchg code was obtained from the atomic_ops project: - - http://www.hpl.hp.com/research/linux/atomic_ops/ - -I (Mathieu Desnoyers) wrote the remainder of the code. - -The license for the library files in this project was therefore changed to -LGPLv2.1 on May 13, 2009, as detailed in LICENSE. diff --git a/tests/Makefile b/tests/Makefile deleted file mode 100644 index ab19097..0000000 --- a/tests/Makefile +++ /dev/null @@ -1 +0,0 @@ -include Makefile.inc diff --git a/tests/Makefile.inc b/tests/Makefile.inc deleted file mode 100644 index 20eef58..0000000 --- a/tests/Makefile.inc +++ /dev/null @@ -1,126 +0,0 @@ - -include ../Makefile.build.inc - -ifeq ($(findstring ${ARCHTYPE},"x86 ppc"),) -APIHEADER=api_gcc.h -else -APIHEADER=api_${ARCHTYPE}.h -endif - -LIBDIR=.. - -CFLAGS+=-I${LIBDIR} - -URCU_SIGNAL=${LIBDIR}/urcu.o ${LIBDIR}/urcu.h -URCU_SIGNAL_YIELD=${LIBDIR}/urcu-yield.o ${LIBDIR}/urcu.h -URCU_MB=${LIBDIR}/urcu-mb.o ${LIBDIR}/urcu.h -URCU_QSBR=${LIBDIR}/urcu-qsbr.o ${LIBDIR}/urcu-qsbr.h -URCU_MB_DEFER=${LIBDIR}/urcu-mb.o ${LIBDIR}/urcu-defer.o ${LIBDIR}/urcu.h - -all: test_urcu test_urcu_dynamic_link test_urcu_timing \ - test_rwlock_timing test_rwlock test_perthreadlock_timing \ - test_perthreadlock test_urcu_yield test_urcu_mb \ - urcu-asm.S test_qsbr_timing test_qsbr urcu-asm.o urcutorture \ - urcutorture-yield test_mutex test_looplen test_urcu_gc \ - test_urcu_gc_mb test_qsbr_gc test_qsbr_lgc test_urcu_lgc \ - test_urcu_lgc_mb test_qsbr_dynamic_link test_urcu_mb_defer \ - test_uatomic - -api.h: ${APIHEADER} - cp -f ${APIHEADER} api.h - -test_looplen: test_looplen.c ${LIBDIR}/urcu.h - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - - -test_urcu: test_urcu.c ${URCU_SIGNAL} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_urcu_gc: test_urcu_gc.c ${URCU_SIGNAL} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_urcu_lgc: test_urcu_gc.c ${URCU_SIGNAL} - $(CC) -DTEST_LOCAL_GC ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - - -test_urcu_mb: test_urcu.c ${URCU_MB} - $(CC) -DURCU_MB ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_urcu_gc_mb: test_urcu_gc.c ${URCU_MB} - $(CC) -DURCU_MB ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_urcu_lgc_mb: test_urcu_gc.c ${URCU_MB} - $(CC) -DTEST_LOCAL_GC -DURCU_MB ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_urcu_mb_defer: test_urcu_defer.c ${URCU_MB_DEFER} - $(CC) -DURCU_MB ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - - -test_qsbr: test_qsbr.c ${URCU_QSBR} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_qsbr_gc: test_qsbr_gc.c ${URCU_QSBR} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_qsbr_lgc: test_qsbr_gc.c ${URCU_QSBR} - $(CC) -DTEST_LOCAL_GC ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_qsbr_dynamic_link: test_qsbr.c ${URCU_QSBR} - $(CC) ${CFLAGS} -DDYNAMIC_LINK_TEST $(LDFLAGS) -o $@ $(SRC_DEP) - - -test_rwlock: test_rwlock.c ${URCU_SIGNAL} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_perthreadlock: test_perthreadlock.c ${URCU_SIGNAL} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_mutex: test_mutex.c ${URCU_SIGNAL} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_urcu_dynamic_link: test_urcu.c ${URCU_SIGNAL} - $(CC) ${CFLAGS} -DDYNAMIC_LINK_TEST $(LDFLAGS) -o $@ $(SRC_DEP) - - -test_urcu_yield: test_urcu.c ${URCU_SIGNAL_YIELD} - $(CC) -DDEBUG_YIELD ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_urcu_timing: test_urcu_timing.c ${URCU_SIGNAL} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_qsbr_timing: test_qsbr_timing.c ${URCU_QSBR} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_rwlock_timing: test_rwlock_timing.c ${URCU_SIGNAL} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_perthreadlock_timing: test_perthreadlock_timing.c ${URCU_SIGNAL} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -urcu-asm.S: urcu-asm.c ${LIBDIR}/urcu.h - $(CC) ${CFLAGS} -S -o $@ $(SRC_DEP) - -urcu-asm.o: urcu-asm.c ${LIBDIR}/urcu.h - $(CC) ${CFLAGS} -c -o $@ $(SRC_DEP) - -urcutorture: urcutorture.c rcutorture.h api.h ${URCU_SIGNAL} - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -urcutorture-yield: urcutorture.c ${URCU_SIGNAL_YIELD} rcutorture.h api.h - $(CC) -DDEBUG_YIELD ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -test_uatomic: test_uatomic.c ../urcu/arch_uatomic.h - $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) - -,PHONY: clean - -clean: - rm -f *.o test_urcu test_urcu_dynamic_link test_urcu_timing \ - test_rwlock_timing test_rwlock test_perthreadlock_timing \ - test_perthreadlock test_urcu_yield test_urcu_mb \ - urcu-asm.S test_qsbr_timing test_qsbr urcutorture \ - urcutorture-yield liburcu.so api.h \ - test_mutex test_urcu_gc test_urcu_gc_mb urcu-asm-1.S \ - test_qsbr_lgc test_qsbr_gc test_looplen test_urcu_lgc \ - test_urcu_lgc_mb test_qsbr_dynamic_link test_urcu_mb_defer \ - test_uatomic diff --git a/tests/Makefile32 b/tests/Makefile32 deleted file mode 100644 index ab57691..0000000 --- a/tests/Makefile32 +++ /dev/null @@ -1,5 +0,0 @@ -include Makefile.inc - -EXTRAMFLAGS=-f Makefile32 -CFLAGS+=-m32 -LDFLAGS+=-m32 diff --git a/tests/Makefile64 b/tests/Makefile64 deleted file mode 100644 index 83ee8da..0000000 --- a/tests/Makefile64 +++ /dev/null @@ -1,5 +0,0 @@ -include Makefile.inc - -EXTRAMFLAGS=-f Makefile64 -CFLAGS+=-m64 -LDFLAGS+=-m64 diff --git a/tests/api_gcc.h b/tests/api_gcc.h deleted file mode 100644 index 1c8b12b..0000000 --- a/tests/api_gcc.h +++ /dev/null @@ -1,1332 +0,0 @@ -#define _INCLUDE_API_H - -/* - * common.h: Common Linux kernel-isms. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; but version 2 of the License only due - * to code included from the Linux kernel. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (c) 2006 Paul E. McKenney, IBM. - * - * Much code taken from the Linux kernel. For such code, the option - * to redistribute under later versions of GPL might not be available. - */ - -#ifndef __always_inline -#define __always_inline inline -#endif - -#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) -#define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1) - -#ifdef __ASSEMBLY__ -# define stringify_in_c(...) __VA_ARGS__ -# define ASM_CONST(x) x -#else -/* This version of stringify will deal with commas... */ -# define __stringify_in_c(...) #__VA_ARGS__ -# define stringify_in_c(...) __stringify_in_c(__VA_ARGS__) " " -# define __ASM_CONST(x) x##UL -# define ASM_CONST(x) __ASM_CONST(x) -#endif - - -/* - * arch-i386.h: Expose x86 atomic instructions. 80486 and better only. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, but version 2 only due to inclusion - * of Linux-kernel code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (c) 2006 Paul E. McKenney, IBM. - * - * Much code taken from the Linux kernel. For such code, the option - * to redistribute under later versions of GPL might not be available. - */ - -/* - * Machine parameters. - */ - -#define CACHE_LINE_SIZE 64 -#define ____cacheline_internodealigned_in_smp \ - __attribute__((__aligned__(1 << 6))) - -#define LOCK_PREFIX "lock ; " - -#if 0 /* duplicate with arch_atomic.h */ -/* - * Atomic data structure, initialization, and access. - */ - -typedef struct { volatile int counter; } atomic_t; - -#define ATOMIC_INIT(i) { (i) } - -#define atomic_read(v) ((v)->counter) -#define atomic_set(v, i) (((v)->counter) = (i)) - -/* - * Atomic operations. - */ - -/** - * atomic_add - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v. - */ - -static __inline__ void atomic_add(int i, atomic_t *v) -{ - (void)__sync_fetch_and_add(&v->counter, i); -} - -/** - * atomic_sub - subtract the atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v. - */ -static __inline__ void atomic_sub(int i, atomic_t *v) -{ - (void)__sync_fetch_and_add(&v->counter, -i); -} - -/** - * atomic_sub_and_test - subtract value from variable and test result - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v and returns - * true if the result is zero, or false for all - * other cases. - */ -static __inline__ int atomic_sub_and_test(int i, atomic_t *v) -{ - return __sync_add_and_fetch(&v->counter, -i) == 0; -} - -/** - * atomic_inc - increment atomic variable - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1. - */ -static __inline__ void atomic_inc(atomic_t *v) -{ - (void)__sync_fetch_and_add(&v->counter, 1); -} - -/** - * atomic_dec - decrement atomic variable - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1. - */ -static __inline__ void atomic_dec(atomic_t *v) -{ - (void)__sync_fetch_and_add(&v->counter, -1); -} - -/** - * atomic_dec_and_test - decrement and test - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1 and - * returns true if the result is 0, or false for all other - * cases. - */ -static __inline__ int atomic_dec_and_test(atomic_t *v) -{ - return __sync_add_and_fetch(&v->counter, -1) == 0; -} - -/** - * atomic_inc_and_test - increment and test - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1 - * and returns true if the result is zero, or false for all - * other cases. - */ -static __inline__ int atomic_inc_and_test(atomic_t *v) -{ - return __sync_add_and_fetch(&v->counter, 1) == 0; -} - -/** - * atomic_add_negative - add and test if negative - * @v: pointer of type atomic_t - * @i: integer value to add - * - * Atomically adds @i to @v and returns true - * if the result is negative, or false when - * result is greater than or equal to zero. - */ -static __inline__ int atomic_add_negative(int i, atomic_t *v) -{ - return __sync_add_and_fetch(&v->counter, i) < 0; -} - -/** - * atomic_add_return - add and return - * @v: pointer of type atomic_t - * @i: integer value to add - * - * Atomically adds @i to @v and returns @i + @v - */ -static __inline__ int atomic_add_return(int i, atomic_t *v) -{ - return __sync_add_and_fetch(&v->counter, i); -} - -static __inline__ int atomic_sub_return(int i, atomic_t *v) -{ - return atomic_add_return(-i,v); -} - -static inline unsigned int -cmpxchg(volatile long *ptr, long oldval, long newval) -{ - return __sync_val_compare_and_swap(ptr, oldval, newval); -} - -#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new)) -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) - -/** - * atomic_add_unless - add unless the number is a given value - * @v: pointer of type atomic_t - * @a: the amount to add to v... - * @u: ...unless v is equal to u. - * - * Atomically adds @a to @v, so long as it was not @u. - * Returns non-zero if @v was not @u, and zero otherwise. - */ -#define atomic_add_unless(v, a, u) \ -({ \ - int c, old; \ - c = atomic_read(v); \ - for (;;) { \ - if (unlikely(c == (u))) \ - break; \ - old = atomic_cmpxchg((v), c, c + (a)); \ - if (likely(old == c)) \ - break; \ - c = old; \ - } \ - c != (u); \ -}) -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) - -#define atomic_inc_return(v) (atomic_add_return(1,v)) -#define atomic_dec_return(v) (atomic_sub_return(1,v)) - -/* Atomic operations are already serializing on x86 */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - -#endif //0 /* duplicate with arch_atomic.h */ - -/* - * api_pthreads.h: API mapping to pthreads environment. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. However, please note that much - * of the code in this file derives from the Linux kernel, and that such - * code may not be available except under GPLv2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (c) 2006 Paul E. McKenney, IBM. - */ - -#include -#include -#include -#include -#include -#define __USE_GNU -#include -#include -#include -/* #include "atomic.h" */ - -/* - * Compiler magic. - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -/* - * Default machine parameters. - */ - -#ifndef CACHE_LINE_SIZE -#define CACHE_LINE_SIZE 128 -#endif /* #ifndef CACHE_LINE_SIZE */ - -/* - * Exclusive locking primitives. - */ - -typedef pthread_mutex_t spinlock_t; - -#define DEFINE_SPINLOCK(lock) spinlock_t lock = PTHREAD_MUTEX_INITIALIZER; -#define __SPIN_LOCK_UNLOCKED(lockp) PTHREAD_MUTEX_INITIALIZER - -static void spin_lock_init(spinlock_t *sp) -{ - if (pthread_mutex_init(sp, NULL) != 0) { - perror("spin_lock_init:pthread_mutex_init"); - exit(-1); - } -} - -static void spin_lock(spinlock_t *sp) -{ - if (pthread_mutex_lock(sp) != 0) { - perror("spin_lock:pthread_mutex_lock"); - exit(-1); - } -} - -static void spin_unlock(spinlock_t *sp) -{ - if (pthread_mutex_unlock(sp) != 0) { - perror("spin_unlock:pthread_mutex_unlock"); - exit(-1); - } -} - -#define spin_lock_irqsave(l, f) do { f = 1; spin_lock(l); } while (0) -#define spin_unlock_irqrestore(l, f) do { f = 0; spin_unlock(l); } while (0) - -/* - * Thread creation/destruction primitives. - */ - -typedef pthread_t thread_id_t; - -#define NR_THREADS 128 - -#define __THREAD_ID_MAP_EMPTY 0 -#define __THREAD_ID_MAP_WAITING 1 -thread_id_t __thread_id_map[NR_THREADS]; -spinlock_t __thread_id_map_mutex; - -#define for_each_thread(t) \ - for (t = 0; t < NR_THREADS; t++) - -#define for_each_running_thread(t) \ - for (t = 0; t < NR_THREADS; t++) \ - if ((__thread_id_map[t] != __THREAD_ID_MAP_EMPTY) && \ - (__thread_id_map[t] != __THREAD_ID_MAP_WAITING)) - -pthread_key_t thread_id_key; - -static int __smp_thread_id(void) -{ - int i; - thread_id_t tid = pthread_self(); - - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == tid) { - long v = i + 1; /* must be non-NULL. */ - - if (pthread_setspecific(thread_id_key, (void *)v) != 0) { - perror("pthread_setspecific"); - exit(-1); - } - return i; - } - } - spin_lock(&__thread_id_map_mutex); - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == tid) - spin_unlock(&__thread_id_map_mutex); - return i; - } - spin_unlock(&__thread_id_map_mutex); - fprintf(stderr, "smp_thread_id: Rogue thread, id: %d(%#x)\n", - (int)tid, (int)tid); - exit(-1); -} - -static int smp_thread_id(void) -{ - void *id; - - id = pthread_getspecific(thread_id_key); - if (id == NULL) - return __smp_thread_id(); - return (long)(id - 1); -} - -static thread_id_t create_thread(void *(*func)(void *), void *arg) -{ - thread_id_t tid; - int i; - - spin_lock(&__thread_id_map_mutex); - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == __THREAD_ID_MAP_EMPTY) - break; - } - if (i >= NR_THREADS) { - spin_unlock(&__thread_id_map_mutex); - fprintf(stderr, "Thread limit of %d exceeded!\n", NR_THREADS); - exit(-1); - } - __thread_id_map[i] = __THREAD_ID_MAP_WAITING; - spin_unlock(&__thread_id_map_mutex); - if (pthread_create(&tid, NULL, func, arg) != 0) { - perror("create_thread:pthread_create"); - exit(-1); - } - __thread_id_map[i] = tid; - return tid; -} - -static void *wait_thread(thread_id_t tid) -{ - int i; - void *vp; - - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == tid) - break; - } - if (i >= NR_THREADS){ - fprintf(stderr, "wait_thread: bad tid = %d(%#x)\n", - (int)tid, (int)tid); - exit(-1); - } - if (pthread_join(tid, &vp) != 0) { - perror("wait_thread:pthread_join"); - exit(-1); - } - __thread_id_map[i] = __THREAD_ID_MAP_EMPTY; - return vp; -} - -static void wait_all_threads(void) -{ - int i; - thread_id_t tid; - - for (i = 1; i < NR_THREADS; i++) { - tid = __thread_id_map[i]; - if (tid != __THREAD_ID_MAP_EMPTY && - tid != __THREAD_ID_MAP_WAITING) - (void)wait_thread(tid); - } -} - -static void run_on(int cpu) -{ - cpu_set_t mask; - - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - sched_setaffinity(0, sizeof(mask), &mask); -} - -/* - * timekeeping -- very crude -- should use MONOTONIC... - */ - -long long get_microseconds(void) -{ - struct timeval tv; - - if (gettimeofday(&tv, NULL) != 0) - abort(); - return ((long long)tv.tv_sec) * 1000000LL + (long long)tv.tv_usec; -} - -/* - * Per-thread variables. - */ - -#define DEFINE_PER_THREAD(type, name) \ - struct { \ - __typeof__(type) v \ - __attribute__((__aligned__(CACHE_LINE_SIZE))); \ - } __per_thread_##name[NR_THREADS]; -#define DECLARE_PER_THREAD(type, name) extern DEFINE_PER_THREAD(type, name) - -#define per_thread(name, thread) __per_thread_##name[thread].v -#define __get_thread_var(name) per_thread(name, smp_thread_id()) - -#define init_per_thread(name, v) \ - do { \ - int __i_p_t_i; \ - for (__i_p_t_i = 0; __i_p_t_i < NR_THREADS; __i_p_t_i++) \ - per_thread(name, __i_p_t_i) = v; \ - } while (0) - -/* - * CPU traversal primitives. - */ - -#ifndef NR_CPUS -#define NR_CPUS 16 -#endif /* #ifndef NR_CPUS */ - -#define for_each_possible_cpu(cpu) \ - for (cpu = 0; cpu < NR_CPUS; cpu++) -#define for_each_online_cpu(cpu) \ - for (cpu = 0; cpu < NR_CPUS; cpu++) - -/* - * Per-CPU variables. - */ - -#define DEFINE_PER_CPU(type, name) \ - struct { \ - __typeof__(type) v \ - __attribute__((__aligned__(CACHE_LINE_SIZE))); \ - } __per_cpu_##name[NR_CPUS] -#define DECLARE_PER_CPU(type, name) extern DEFINE_PER_CPU(type, name) - -DEFINE_PER_THREAD(int, smp_processor_id); - -#define per_cpu(name, thread) __per_cpu_##name[thread].v -#define __get_cpu_var(name) per_cpu(name, smp_processor_id()) - -#define init_per_cpu(name, v) \ - do { \ - int __i_p_c_i; \ - for (__i_p_c_i = 0; __i_p_c_i < NR_CPUS; __i_p_c_i++) \ - per_cpu(name, __i_p_c_i) = v; \ - } while (0) - -/* - * CPU state checking (crowbarred). - */ - -#define idle_cpu(cpu) 0 -#define in_softirq() 1 -#define hardirq_count() 0 -#define PREEMPT_SHIFT 0 -#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) -#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) -#define PREEMPT_BITS 8 -#define SOFTIRQ_BITS 8 - -/* - * CPU hotplug. - */ - -struct notifier_block { - int (*notifier_call)(struct notifier_block *, unsigned long, void *); - struct notifier_block *next; - int priority; -}; - -#define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */ -#define CPU_UP_PREPARE 0x0003 /* CPU (unsigned)v coming up */ -#define CPU_UP_CANCELED 0x0004 /* CPU (unsigned)v NOT coming up */ -#define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */ -#define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */ -#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */ -#define CPU_DYING 0x0008 /* CPU (unsigned)v not running any task, - * not handling interrupts, soon dead */ -#define CPU_POST_DEAD 0x0009 /* CPU (unsigned)v dead, cpu_hotplug - * lock is dropped */ - -/* Used for CPU hotplug events occuring while tasks are frozen due to a suspend - * operation in progress - */ -#define CPU_TASKS_FROZEN 0x0010 - -#define CPU_ONLINE_FROZEN (CPU_ONLINE | CPU_TASKS_FROZEN) -#define CPU_UP_PREPARE_FROZEN (CPU_UP_PREPARE | CPU_TASKS_FROZEN) -#define CPU_UP_CANCELED_FROZEN (CPU_UP_CANCELED | CPU_TASKS_FROZEN) -#define CPU_DOWN_PREPARE_FROZEN (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN) -#define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN) -#define CPU_DEAD_FROZEN (CPU_DEAD | CPU_TASKS_FROZEN) -#define CPU_DYING_FROZEN (CPU_DYING | CPU_TASKS_FROZEN) - -/* Hibernation and suspend events */ -#define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */ -#define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */ -#define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */ -#define PM_POST_SUSPEND 0x0004 /* Suspend finished */ -#define PM_RESTORE_PREPARE 0x0005 /* Going to restore a saved image */ -#define PM_POST_RESTORE 0x0006 /* Restore failed */ - -#define NOTIFY_DONE 0x0000 /* Don't care */ -#define NOTIFY_OK 0x0001 /* Suits me */ -#define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ -#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) - /* Bad/Veto action */ -/* - * Clean way to return from the notifier and stop further calls. - */ -#define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK) - -/* - * Bug checks. - */ - -#define BUG_ON(c) do { if (!(c)) abort(); } while (0) - -/* - * Initialization -- Must be called before calling any primitives. - */ - -static void smp_init(void) -{ - int i; - - spin_lock_init(&__thread_id_map_mutex); - __thread_id_map[0] = pthread_self(); - for (i = 1; i < NR_THREADS; i++) - __thread_id_map[i] = __THREAD_ID_MAP_EMPTY; - init_per_thread(smp_processor_id, 0); - if (pthread_key_create(&thread_id_key, NULL) != 0) { - perror("pthread_key_create"); - exit(-1); - } -} - -/* Taken from the Linux kernel source tree, so GPLv2-only!!! */ - -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#if 0 -/* - * 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. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -#ifndef CONFIG_DEBUG_LIST -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} -#else -extern void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next); -#endif - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = 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. - */ -#ifndef CONFIG_DEBUG_LIST -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} -#else -extern void list_del(struct list_head *entry); -#endif - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -/** - * list_is_singular - tests whether a list has just one entry. - * @head: the list to test. - */ -static inline int list_is_singular(const struct list_head *head) -{ - return !list_empty(head) && (head->next == head->prev); -} - -static inline void __list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) -{ - struct list_head *new_first = entry->next; - list->next = head->next; - list->next->prev = list; - list->prev = entry; - entry->next = list; - head->next = new_first; - new_first->prev = head; -} - -/** - * list_cut_position - cut a list into two - * @list: a new list to add all removed entries - * @head: a list with entries - * @entry: an entry within head, could be the head itself - * and if so we won't cut the list - * - * This helper moves the initial part of @head, up to and - * including @entry, from @head to @list. You should - * pass on @entry an element you know is on @head. @list - * should be an empty list or a list you do not care about - * losing its data. - * - */ -static inline void list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) -{ - if (list_empty(head)) - return; - if (list_is_singular(head) && - (head->next != entry && head != entry)) - return; - if (entry == head) - INIT_LIST_HEAD(list); - else - __list_cut_position(list, head, entry); -} - -static inline void __list_splice(const struct list_head *list, - struct list_head *prev, - struct list_head *next) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - - first->prev = prev; - prev->next = first; - - last->next = next; - next->prev = last; -} - -/** - * list_splice - join two lists, this is designed for stacks - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(const struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head, head->next); -} - -/** - * list_splice_tail - join two lists, each list being a queue - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice_tail(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head->prev, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head, head->next); - INIT_LIST_HEAD(list); - } -} - -/** - * list_splice_tail_init - join two lists and reinitialise the emptied list - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * Each of the lists is a queue. - * The list at @list is reinitialised - */ -static inline void list_splice_tail_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head->prev, head); - INIT_LIST_HEAD(list); - } -} - -/** - * 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. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; prefetch(pos->next), pos != (head); \ - pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - prefetch(pos->prev), pos != (head); \ - pos = n, n = pos->prev) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -#endif //0 - -/* - * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -static inline void INIT_HLIST_NODE(struct hlist_node *h) -{ - h->next = NULL; - h->pprev = NULL; -} - -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; -} - -static inline void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; -} - -static inline void hlist_del_init(struct hlist_node *n) -{ - if (!hlist_unhashed(n)) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - -/* next must be != NULL */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; -} - -static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) -{ - next->next = n->next; - n->next = next; - next->pprev = &n->next; - - if(next->next) - next->next->pprev = &next->next; -} - -/* - * Move a list from one list head to another. Fixup the pprev - * reference of the first entry if it exists. - */ -static inline void hlist_move_list(struct hlist_head *old, - struct hlist_head *new) -{ - new->first = old->first; - if (new->first) - new->first->pprev = &new->first; - old->first = NULL; -} - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) - -/** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) - -#endif diff --git a/tests/api_ppc.h b/tests/api_ppc.h deleted file mode 100644 index 3ca5270..0000000 --- a/tests/api_ppc.h +++ /dev/null @@ -1,1706 +0,0 @@ -/* MECHANICALLY GENERATED, DO NOT EDIT!!! */ - -#define _INCLUDE_API_H - -/* - * common.h: Common Linux kernel-isms. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; but version 2 of the License only due - * to code included from the Linux kernel. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (c) 2006 Paul E. McKenney, IBM. - * - * Much code taken from the Linux kernel. For such code, the option - * to redistribute under later versions of GPL might not be available. - */ - -#include - -#ifndef __always_inline -#define __always_inline inline -#endif - -#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) -#define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1) - -#ifdef __ASSEMBLY__ -# define stringify_in_c(...) __VA_ARGS__ -# define ASM_CONST(x) x -#else -/* This version of stringify will deal with commas... */ -# define __stringify_in_c(...) #__VA_ARGS__ -# define stringify_in_c(...) __stringify_in_c(__VA_ARGS__) " " -# define __ASM_CONST(x) x##UL -# define ASM_CONST(x) __ASM_CONST(x) -#endif - - -/* - * arch-ppc64.h: Expose PowerPC atomic instructions. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; but version 2 of the License only due - * to code included from the Linux kernel. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (c) 2006 Paul E. McKenney, IBM. - * - * Much code taken from the Linux kernel. For such code, the option - * to redistribute under later versions of GPL might not be available. - */ - -/* - * Machine parameters. - */ - -#define CONFIG_PPC64 - -/*#define CACHE_LINE_SIZE 128 */ -#define ____cacheline_internodealigned_in_smp \ - __attribute__((__aligned__(1 << 7))) - -#if 0 /* duplicate with arch_atomic.h */ - -/* - * Atomic data structure, initialization, and access. - */ - -typedef struct { volatile int counter; } atomic_t; - -#define ATOMIC_INIT(i) { (i) } - -#define atomic_read(v) ((v)->counter) -#define atomic_set(v, i) (((v)->counter) = (i)) - -/* - * Atomic operations. - */ - -#define LWSYNC lwsync -#define PPC405_ERR77(ra,rb) -#ifdef CONFIG_SMP -# define LWSYNC_ON_SMP stringify_in_c(LWSYNC) "\n" -# define ISYNC_ON_SMP "\n\tisync\n" -#else -# define LWSYNC_ON_SMP -# define ISYNC_ON_SMP -#endif - -/* - * Atomic exchange - * - * Changes the memory location '*ptr' to be val and returns - * the previous value stored there. - */ -static __always_inline unsigned long -__xchg_u32(volatile void *p, unsigned long val) -{ - unsigned long prev; - - __asm__ __volatile__( - LWSYNC_ON_SMP -"1: lwarx %0,0,%2 \n" - PPC405_ERR77(0,%2) -" stwcx. %3,0,%2 \n\ - bne- 1b" - ISYNC_ON_SMP - : "=&r" (prev), "+m" (*(volatile unsigned int *)p) - : "r" (p), "r" (val) - : "cc", "memory"); - - return prev; -} - -/* - * Atomic exchange - * - * Changes the memory location '*ptr' to be val and returns - * the previous value stored there. - */ -static __always_inline unsigned long -__xchg_u32_local(volatile void *p, unsigned long val) -{ - unsigned long prev; - - __asm__ __volatile__( -"1: lwarx %0,0,%2 \n" - PPC405_ERR77(0,%2) -" stwcx. %3,0,%2 \n\ - bne- 1b" - : "=&r" (prev), "+m" (*(volatile unsigned int *)p) - : "r" (p), "r" (val) - : "cc", "memory"); - - return prev; -} - -#ifdef CONFIG_PPC64 -static __always_inline unsigned long -__xchg_u64(volatile void *p, unsigned long val) -{ - unsigned long prev; - - __asm__ __volatile__( - LWSYNC_ON_SMP -"1: ldarx %0,0,%2 \n" - PPC405_ERR77(0,%2) -" stdcx. %3,0,%2 \n\ - bne- 1b" - ISYNC_ON_SMP - : "=&r" (prev), "+m" (*(volatile unsigned long *)p) - : "r" (p), "r" (val) - : "cc", "memory"); - - return prev; -} - -static __always_inline unsigned long -__xchg_u64_local(volatile void *p, unsigned long val) -{ - unsigned long prev; - - __asm__ __volatile__( -"1: ldarx %0,0,%2 \n" - PPC405_ERR77(0,%2) -" stdcx. %3,0,%2 \n\ - bne- 1b" - : "=&r" (prev), "+m" (*(volatile unsigned long *)p) - : "r" (p), "r" (val) - : "cc", "memory"); - - return prev; -} -#endif - -/* - * This function doesn't exist, so you'll get a linker error - * if something tries to do an invalid xchg(). - */ -extern void __xchg_called_with_bad_pointer(void); - -static __always_inline unsigned long -__xchg(volatile void *ptr, unsigned long x, unsigned int size) -{ - switch (size) { - case 4: - return __xchg_u32(ptr, x); -#ifdef CONFIG_PPC64 - case 8: - return __xchg_u64(ptr, x); -#endif - } - __xchg_called_with_bad_pointer(); - return x; -} - -static __always_inline unsigned long -__xchg_local(volatile void *ptr, unsigned long x, unsigned int size) -{ - switch (size) { - case 4: - return __xchg_u32_local(ptr, x); -#ifdef CONFIG_PPC64 - case 8: - return __xchg_u64_local(ptr, x); -#endif - } - __xchg_called_with_bad_pointer(); - return x; -} -#define xchg(ptr,x) \ - ({ \ - __typeof__(*(ptr)) _x_ = (x); \ - (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \ - }) - -#define xchg_local(ptr,x) \ - ({ \ - __typeof__(*(ptr)) _x_ = (x); \ - (__typeof__(*(ptr))) __xchg_local((ptr), \ - (unsigned long)_x_, sizeof(*(ptr))); \ - }) - -/* - * Compare and exchange - if *p == old, set it to new, - * and return the old value of *p. - */ -#define __HAVE_ARCH_CMPXCHG 1 - -static __always_inline unsigned long -__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new) -{ - unsigned int prev; - - __asm__ __volatile__ ( - LWSYNC_ON_SMP -"1: lwarx %0,0,%2 # __cmpxchg_u32\n\ - cmpw 0,%0,%3\n\ - bne- 2f\n" - PPC405_ERR77(0,%2) -" stwcx. %4,0,%2\n\ - bne- 1b" - ISYNC_ON_SMP - "\n\ -2:" - : "=&r" (prev), "+m" (*p) - : "r" (p), "r" (old), "r" (new) - : "cc", "memory"); - - return prev; -} - -static __always_inline unsigned long -__cmpxchg_u32_local(volatile unsigned int *p, unsigned long old, - unsigned long new) -{ - unsigned int prev; - - __asm__ __volatile__ ( -"1: lwarx %0,0,%2 # __cmpxchg_u32\n\ - cmpw 0,%0,%3\n\ - bne- 2f\n" - PPC405_ERR77(0,%2) -" stwcx. %4,0,%2\n\ - bne- 1b" - "\n\ -2:" - : "=&r" (prev), "+m" (*p) - : "r" (p), "r" (old), "r" (new) - : "cc", "memory"); - - return prev; -} - -#ifdef CONFIG_PPC64 -static __always_inline unsigned long -__cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new) -{ - unsigned long prev; - - __asm__ __volatile__ ( - LWSYNC_ON_SMP -"1: ldarx %0,0,%2 # __cmpxchg_u64\n\ - cmpd 0,%0,%3\n\ - bne- 2f\n\ - stdcx. %4,0,%2\n\ - bne- 1b" - ISYNC_ON_SMP - "\n\ -2:" - : "=&r" (prev), "+m" (*p) - : "r" (p), "r" (old), "r" (new) - : "cc", "memory"); - - return prev; -} - -static __always_inline unsigned long -__cmpxchg_u64_local(volatile unsigned long *p, unsigned long old, - unsigned long new) -{ - unsigned long prev; - - __asm__ __volatile__ ( -"1: ldarx %0,0,%2 # __cmpxchg_u64\n\ - cmpd 0,%0,%3\n\ - bne- 2f\n\ - stdcx. %4,0,%2\n\ - bne- 1b" - "\n\ -2:" - : "=&r" (prev), "+m" (*p) - : "r" (p), "r" (old), "r" (new) - : "cc", "memory"); - - return prev; -} -#endif - -/* This function doesn't exist, so you'll get a linker error - if something tries to do an invalid cmpxchg(). */ -extern void __cmpxchg_called_with_bad_pointer(void); - -static __always_inline unsigned long -__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, - unsigned int size) -{ - switch (size) { - case 4: - return __cmpxchg_u32(ptr, old, new); -#ifdef CONFIG_PPC64 - case 8: - return __cmpxchg_u64(ptr, old, new); -#endif - } - __cmpxchg_called_with_bad_pointer(); - return old; -} - -static __always_inline unsigned long -__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new, - unsigned int size) -{ - switch (size) { - case 4: - return __cmpxchg_u32_local(ptr, old, new); -#ifdef CONFIG_PPC64 - case 8: - return __cmpxchg_u64_local(ptr, old, new); -#endif - } - __cmpxchg_called_with_bad_pointer(); - return old; -} - -#define cmpxchg(ptr, o, n) \ - ({ \ - __typeof__(*(ptr)) _o_ = (o); \ - __typeof__(*(ptr)) _n_ = (n); \ - (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ - (unsigned long)_n_, sizeof(*(ptr))); \ - }) - - -#define cmpxchg_local(ptr, o, n) \ - ({ \ - __typeof__(*(ptr)) _o_ = (o); \ - __typeof__(*(ptr)) _n_ = (n); \ - (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_, \ - (unsigned long)_n_, sizeof(*(ptr))); \ - }) - -#ifdef CONFIG_PPC64 -/* - * We handle most unaligned accesses in hardware. On the other hand - * unaligned DMA can be very expensive on some ppc64 IO chips (it does - * powers of 2 writes until it reaches sufficient alignment). - * - * Based on this we disable the IP header alignment in network drivers. - * We also modify NET_SKB_PAD to be a cacheline in size, thus maintaining - * cacheline alignment of buffers. - */ -#define NET_IP_ALIGN 0 -#define NET_SKB_PAD L1_CACHE_BYTES - -#define cmpxchg64(ptr, o, n) \ - ({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ - cmpxchg((ptr), (o), (n)); \ - }) -#define cmpxchg64_local(ptr, o, n) \ - ({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ - cmpxchg_local((ptr), (o), (n)); \ - }) -#endif - -#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) - -/** - * atomic_add - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @a to @v. - */ -static __inline__ void atomic_add(int a, atomic_t *v) -{ - int t; - - __asm__ __volatile__( - "1: lwarx %0,0,%3 # atomic_add\n\ - add %0,%2,%0 \n\ - stwcx. %0,0,%3 \n\ - bne- 1b" - : "=&r" (t), "+m" (v->counter) - : "r" (a), "r" (&v->counter) - : "cc"); -} - -/** - * atomic_sub - subtract the atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @a from @v. - */ -static __inline__ void atomic_sub(int a, atomic_t *v) -{ - int t; - - __asm__ __volatile__( - "1: lwarx %0,0,%3 # atomic_sub \n\ - subf %0,%2,%0 \n\ - stwcx. %0,0,%3 \n\ - bne- 1b" - : "=&r" (t), "+m" (v->counter) - : "r" (a), "r" (&v->counter) - : "cc"); -} - -static __inline__ atomic_sub_return(int a, atomic_t *v) -{ - int t; - - __asm__ __volatile__( - "lwsync\n\ - 1: lwarx %0,0,%2 # atomic_sub_return\n\ - subf %0,%1,%0\n\ - stwcx. %0,0,%2 \n\ - bne- 1b \n\ - isync" - : "=&r" (t) - : "r" (a), "r" (&v->counter) - : "cc", "memory"); - - return t; -} - -/** - * atomic_sub_and_test - subtract value from variable and test result - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v and returns - * true if the result is zero, or false for all - * other cases. - */ -static __inline__ int atomic_sub_and_test(int a, atomic_t *v) -{ - return atomic_sub_return(a, v) == 0; -} - -/** - * atomic_inc - increment atomic variable - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1. - */ -static __inline__ void atomic_inc(atomic_t *v) -{ - atomic_add(1, v); -} - -/** - * atomic_dec - decrement atomic variable - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1. - */ -static __inline__ void atomic_dec(atomic_t *v) -{ - atomic_sub(1, v); -} - -/** - * atomic_dec_and_test - decrement and test - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1 and - * returns true if the result is 0, or false for all other - * cases. - */ -static __inline__ int atomic_dec_and_test(atomic_t *v) -{ - return atomic_sub_and_test(1, v); -} - -/** - * atomic_inc_and_test - increment and test - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1 - * and returns true if the result is zero, or false for all - * other cases. - */ -static __inline__ int atomic_inc_and_test(atomic_t *v) -{ - return atomic_inc_return(v); -} - -/** - * atomic_add_return - add and return - * @v: pointer of type atomic_t - * @i: integer value to add - * - * Atomically adds @i to @v and returns @i + @v - */ -static __inline__ int atomic_add_return(int a, atomic_t *v) -{ - int t; - - __asm__ __volatile__( - "lwsync \n\ - 1: lwarx %0,0,%2 # atomic_add_return \n\ - add %0,%1,%0 \n\ - stwcx. %0,0,%2 \n\ - bne- 1b \n\ - isync" - : "=&r" (t) - : "r" (a), "r" (&v->counter) - : "cc", "memory"); - - return t; -} - -/** - * atomic_add_negative - add and test if negative - * @v: pointer of type atomic_t - * @i: integer value to add - * - * Atomically adds @i to @v and returns true - * if the result is negative, or false when - * result is greater than or equal to zero. - */ -static __inline__ int atomic_add_negative(int a, atomic_t *v) -{ - return atomic_add_return(a, v) < 0; -} - -/** - * atomic_add_unless - add unless the number is a given value - * @v: pointer of type atomic_t - * @a: the amount to add to v... - * @u: ...unless v is equal to u. - * - * Atomically adds @a to @v, so long as it was not @u. - * Returns non-zero if @v was not @u, and zero otherwise. - */ -static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) -{ - int t; - - __asm__ __volatile__( - "lwsync \n\ - 1: lwarx %0,0,%1 # atomic_add_unless\n\ - cmpd 0,%0,%3 \n\ - beq- 2f \n\ - add %0,%2,%0 \n\ - stwcx. %0,0,%1 \n\ - bne- 1b \n\ - isync \n\ - subf %0,%2,%0 \n\ - 2:" - : "=&r" (t) - : "r" (&v->counter), "r" (a), "r" (u) - : "cc", "memory"); - - return t != u; -} - -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) - -#define atomic_inc_return(v) (atomic_add_return(1,v)) -#define atomic_dec_return(v) (atomic_sub_return(1,v)) - -/* Atomic operations are already serializing on x86 */ -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__after_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_inc() smp_mb() - -#endif //0 /* duplicate with arch_atomic.h */ - -/* - * api_pthreads.h: API mapping to pthreads environment. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. However, please note that much - * of the code in this file derives from the Linux kernel, and that such - * code may not be available except under GPLv2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (c) 2006 Paul E. McKenney, IBM. - */ - -#include -#include -#include -#include -#include -#define __USE_GNU -#include -#include -#include -/* #include "atomic.h" */ - -/* - * Compiler magic. - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -/* - * Default machine parameters. - */ - -#ifndef CACHE_LINE_SIZE -/* #define CACHE_LINE_SIZE 128 */ -#endif /* #ifndef CACHE_LINE_SIZE */ - -/* - * Exclusive locking primitives. - */ - -typedef pthread_mutex_t spinlock_t; - -#define DEFINE_SPINLOCK(lock) spinlock_t lock = PTHREAD_MUTEX_INITIALIZER; -#define __SPIN_LOCK_UNLOCKED(lockp) PTHREAD_MUTEX_INITIALIZER - -static void spin_lock_init(spinlock_t *sp) -{ - if (pthread_mutex_init(sp, NULL) != 0) { - perror("spin_lock_init:pthread_mutex_init"); - exit(-1); - } -} - -static void spin_lock(spinlock_t *sp) -{ - if (pthread_mutex_lock(sp) != 0) { - perror("spin_lock:pthread_mutex_lock"); - exit(-1); - } -} - -static void spin_unlock(spinlock_t *sp) -{ - if (pthread_mutex_unlock(sp) != 0) { - perror("spin_unlock:pthread_mutex_unlock"); - exit(-1); - } -} - -#define spin_lock_irqsave(l, f) do { f = 1; spin_lock(l); } while (0) -#define spin_unlock_irqrestore(l, f) do { f = 0; spin_unlock(l); } while (0) - -/* - * Thread creation/destruction primitives. - */ - -typedef pthread_t thread_id_t; - -#define NR_THREADS 128 - -#define __THREAD_ID_MAP_EMPTY 0 -#define __THREAD_ID_MAP_WAITING 1 -thread_id_t __thread_id_map[NR_THREADS]; -spinlock_t __thread_id_map_mutex; - -#define for_each_thread(t) \ - for (t = 0; t < NR_THREADS; t++) - -#define for_each_running_thread(t) \ - for (t = 0; t < NR_THREADS; t++) \ - if ((__thread_id_map[t] != __THREAD_ID_MAP_EMPTY) && \ - (__thread_id_map[t] != __THREAD_ID_MAP_WAITING)) - -#define for_each_tid(t, tid) \ - for (t = 0; t < NR_THREADS; t++) \ - if ((((tid) = __thread_id_map[t]) != __THREAD_ID_MAP_EMPTY) && \ - ((tid) != __THREAD_ID_MAP_WAITING)) - -pthread_key_t thread_id_key; - -static int __smp_thread_id(void) -{ - int i; - thread_id_t tid = pthread_self(); - - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == tid) { - long v = i + 1; /* must be non-NULL. */ - - if (pthread_setspecific(thread_id_key, (void *)v) != 0) { - perror("pthread_setspecific"); - exit(-1); - } - return i; - } - } - spin_lock(&__thread_id_map_mutex); - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == tid) - spin_unlock(&__thread_id_map_mutex); - return i; - } - spin_unlock(&__thread_id_map_mutex); - fprintf(stderr, "smp_thread_id: Rogue thread, id: %d(%#x)\n", - (int)tid, (int)tid); - exit(-1); -} - -static int smp_thread_id(void) -{ - void *id; - - id = pthread_getspecific(thread_id_key); - if (id == NULL) - return __smp_thread_id(); - return (long)(id - 1); -} - -static thread_id_t create_thread(void *(*func)(void *), void *arg) -{ - thread_id_t tid; - int i; - - spin_lock(&__thread_id_map_mutex); - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == __THREAD_ID_MAP_EMPTY) - break; - } - if (i >= NR_THREADS) { - spin_unlock(&__thread_id_map_mutex); - fprintf(stderr, "Thread limit of %d exceeded!\n", NR_THREADS); - exit(-1); - } - __thread_id_map[i] = __THREAD_ID_MAP_WAITING; - spin_unlock(&__thread_id_map_mutex); - if (pthread_create(&tid, NULL, func, arg) != 0) { - perror("create_thread:pthread_create"); - exit(-1); - } - __thread_id_map[i] = tid; - return tid; -} - -static void *wait_thread(thread_id_t tid) -{ - int i; - void *vp; - - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == tid) - break; - } - if (i >= NR_THREADS){ - fprintf(stderr, "wait_thread: bad tid = %d(%#x)\n", - (int)tid, (int)tid); - exit(-1); - } - if (pthread_join(tid, &vp) != 0) { - perror("wait_thread:pthread_join"); - exit(-1); - } - __thread_id_map[i] = __THREAD_ID_MAP_EMPTY; - return vp; -} - -static void wait_all_threads(void) -{ - int i; - thread_id_t tid; - - for (i = 1; i < NR_THREADS; i++) { - tid = __thread_id_map[i]; - if (tid != __THREAD_ID_MAP_EMPTY && - tid != __THREAD_ID_MAP_WAITING) - (void)wait_thread(tid); - } -} - -static void run_on(int cpu) -{ - cpu_set_t mask; - - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - sched_setaffinity(0, sizeof(mask), &mask); -} - -/* - * timekeeping -- very crude -- should use MONOTONIC... - */ - -long long get_microseconds(void) -{ - struct timeval tv; - - if (gettimeofday(&tv, NULL) != 0) - abort(); - return ((long long)tv.tv_sec) * 1000000LL + (long long)tv.tv_usec; -} - -/* - * Per-thread variables. - */ - -#define DEFINE_PER_THREAD(type, name) \ - struct { \ - __typeof__(type) v \ - __attribute__((__aligned__(CACHE_LINE_SIZE))); \ - } __per_thread_##name[NR_THREADS]; -#define DECLARE_PER_THREAD(type, name) extern DEFINE_PER_THREAD(type, name) - -#define per_thread(name, thread) __per_thread_##name[thread].v -#define __get_thread_var(name) per_thread(name, smp_thread_id()) - -#define init_per_thread(name, v) \ - do { \ - int __i_p_t_i; \ - for (__i_p_t_i = 0; __i_p_t_i < NR_THREADS; __i_p_t_i++) \ - per_thread(name, __i_p_t_i) = v; \ - } while (0) - -/* - * CPU traversal primitives. - */ - -#ifndef NR_CPUS -#define NR_CPUS 16 -#endif /* #ifndef NR_CPUS */ - -#define for_each_possible_cpu(cpu) \ - for (cpu = 0; cpu < NR_CPUS; cpu++) -#define for_each_online_cpu(cpu) \ - for (cpu = 0; cpu < NR_CPUS; cpu++) - -/* - * Per-CPU variables. - */ - -#define DEFINE_PER_CPU(type, name) \ - struct { \ - __typeof__(type) v \ - __attribute__((__aligned__(CACHE_LINE_SIZE))); \ - } __per_cpu_##name[NR_CPUS] -#define DECLARE_PER_CPU(type, name) extern DEFINE_PER_CPU(type, name) - -DEFINE_PER_THREAD(int, smp_processor_id); - -#define per_cpu(name, thread) __per_cpu_##name[thread].v -#define __get_cpu_var(name) per_cpu(name, smp_processor_id()) - -#define init_per_cpu(name, v) \ - do { \ - int __i_p_c_i; \ - for (__i_p_c_i = 0; __i_p_c_i < NR_CPUS; __i_p_c_i++) \ - per_cpu(name, __i_p_c_i) = v; \ - } while (0) - -/* - * CPU state checking (crowbarred). - */ - -#define idle_cpu(cpu) 0 -#define in_softirq() 1 -#define hardirq_count() 0 -#define PREEMPT_SHIFT 0 -#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) -#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) -#define PREEMPT_BITS 8 -#define SOFTIRQ_BITS 8 - -/* - * CPU hotplug. - */ - -struct notifier_block { - int (*notifier_call)(struct notifier_block *, unsigned long, void *); - struct notifier_block *next; - int priority; -}; - -#define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */ -#define CPU_UP_PREPARE 0x0003 /* CPU (unsigned)v coming up */ -#define CPU_UP_CANCELED 0x0004 /* CPU (unsigned)v NOT coming up */ -#define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */ -#define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */ -#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */ -#define CPU_DYING 0x0008 /* CPU (unsigned)v not running any task, - * not handling interrupts, soon dead */ -#define CPU_POST_DEAD 0x0009 /* CPU (unsigned)v dead, cpu_hotplug - * lock is dropped */ - -/* Used for CPU hotplug events occuring while tasks are frozen due to a suspend - * operation in progress - */ -#define CPU_TASKS_FROZEN 0x0010 - -#define CPU_ONLINE_FROZEN (CPU_ONLINE | CPU_TASKS_FROZEN) -#define CPU_UP_PREPARE_FROZEN (CPU_UP_PREPARE | CPU_TASKS_FROZEN) -#define CPU_UP_CANCELED_FROZEN (CPU_UP_CANCELED | CPU_TASKS_FROZEN) -#define CPU_DOWN_PREPARE_FROZEN (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN) -#define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN) -#define CPU_DEAD_FROZEN (CPU_DEAD | CPU_TASKS_FROZEN) -#define CPU_DYING_FROZEN (CPU_DYING | CPU_TASKS_FROZEN) - -/* Hibernation and suspend events */ -#define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */ -#define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */ -#define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */ -#define PM_POST_SUSPEND 0x0004 /* Suspend finished */ -#define PM_RESTORE_PREPARE 0x0005 /* Going to restore a saved image */ -#define PM_POST_RESTORE 0x0006 /* Restore failed */ - -#define NOTIFY_DONE 0x0000 /* Don't care */ -#define NOTIFY_OK 0x0001 /* Suits me */ -#define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ -#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) - /* Bad/Veto action */ -/* - * Clean way to return from the notifier and stop further calls. - */ -#define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK) - -/* - * Bug checks. - */ - -#define BUG_ON(c) do { if (!(c)) abort(); } while (0) - -/* - * Initialization -- Must be called before calling any primitives. - */ - -static void smp_init(void) -{ - int i; - - spin_lock_init(&__thread_id_map_mutex); - __thread_id_map[0] = pthread_self(); - for (i = 1; i < NR_THREADS; i++) - __thread_id_map[i] = __THREAD_ID_MAP_EMPTY; - init_per_thread(smp_processor_id, 0); - if (pthread_key_create(&thread_id_key, NULL) != 0) { - perror("pthread_key_create"); - exit(-1); - } -} - -/* Taken from the Linux kernel source tree, so GPLv2-only!!! */ - -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#if 0 - -/* - * 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. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -#ifndef CONFIG_DEBUG_LIST -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} -#else -extern void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next); -#endif - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = 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. - */ -#ifndef CONFIG_DEBUG_LIST -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} -#else -extern void list_del(struct list_head *entry); -#endif - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -/** - * list_is_singular - tests whether a list has just one entry. - * @head: the list to test. - */ -static inline int list_is_singular(const struct list_head *head) -{ - return !list_empty(head) && (head->next == head->prev); -} - -static inline void __list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) -{ - struct list_head *new_first = entry->next; - list->next = head->next; - list->next->prev = list; - list->prev = entry; - entry->next = list; - head->next = new_first; - new_first->prev = head; -} - -/** - * list_cut_position - cut a list into two - * @list: a new list to add all removed entries - * @head: a list with entries - * @entry: an entry within head, could be the head itself - * and if so we won't cut the list - * - * This helper moves the initial part of @head, up to and - * including @entry, from @head to @list. You should - * pass on @entry an element you know is on @head. @list - * should be an empty list or a list you do not care about - * losing its data. - * - */ -static inline void list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) -{ - if (list_empty(head)) - return; - if (list_is_singular(head) && - (head->next != entry && head != entry)) - return; - if (entry == head) - INIT_LIST_HEAD(list); - else - __list_cut_position(list, head, entry); -} - -static inline void __list_splice(const struct list_head *list, - struct list_head *prev, - struct list_head *next) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - - first->prev = prev; - prev->next = first; - - last->next = next; - next->prev = last; -} - -/** - * list_splice - join two lists, this is designed for stacks - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(const struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head, head->next); -} - -/** - * list_splice_tail - join two lists, each list being a queue - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice_tail(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head->prev, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head, head->next); - INIT_LIST_HEAD(list); - } -} - -/** - * list_splice_tail_init - join two lists and reinitialise the emptied list - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * Each of the lists is a queue. - * The list at @list is reinitialised - */ -static inline void list_splice_tail_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head->prev, head); - INIT_LIST_HEAD(list); - } -} - -/** - * 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. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; prefetch(pos->next), pos != (head); \ - pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - prefetch(pos->prev), pos != (head); \ - pos = n, n = pos->prev) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -#endif //0 - -/* - * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -static inline void INIT_HLIST_NODE(struct hlist_node *h) -{ - h->next = NULL; - h->pprev = NULL; -} - -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; -} - -static inline void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; -} - -static inline void hlist_del_init(struct hlist_node *n) -{ - if (!hlist_unhashed(n)) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - -/* next must be != NULL */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; -} - -static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) -{ - next->next = n->next; - n->next = next; - next->pprev = &n->next; - - if(next->next) - next->next->pprev = &next->next; -} - -/* - * Move a list from one list head to another. Fixup the pprev - * reference of the first entry if it exists. - */ -static inline void hlist_move_list(struct hlist_head *old, - struct hlist_head *new) -{ - new->first = old->first; - if (new->first) - new->first->pprev = &new->first; - old->first = NULL; -} - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) - -/** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) - -#endif diff --git a/tests/api_x86.h b/tests/api_x86.h deleted file mode 100644 index 4f6e836..0000000 --- a/tests/api_x86.h +++ /dev/null @@ -1,1395 +0,0 @@ -/* MECHANICALLY GENERATED, DO NOT EDIT!!! */ - -#define _INCLUDE_API_H - -/* - * common.h: Common Linux kernel-isms. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; but version 2 of the License only due - * to code included from the Linux kernel. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (c) 2006 Paul E. McKenney, IBM. - * - * Much code taken from the Linux kernel. For such code, the option - * to redistribute under later versions of GPL might not be available. - */ - -#include - -#ifndef __always_inline -#define __always_inline inline -#endif - -#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) -#define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1) - -#ifdef __ASSEMBLY__ -# define stringify_in_c(...) __VA_ARGS__ -# define ASM_CONST(x) x -#else -/* This version of stringify will deal with commas... */ -# define __stringify_in_c(...) #__VA_ARGS__ -# define stringify_in_c(...) __stringify_in_c(__VA_ARGS__) " " -# define __ASM_CONST(x) x##UL -# define ASM_CONST(x) __ASM_CONST(x) -#endif - - -/* - * arch-i386.h: Expose x86 atomic instructions. 80486 and better only. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, but version 2 only due to inclusion - * of Linux-kernel code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (c) 2006 Paul E. McKenney, IBM. - * - * Much code taken from the Linux kernel. For such code, the option - * to redistribute under later versions of GPL might not be available. - */ - -/* - * Machine parameters. - */ - -/* #define CACHE_LINE_SIZE 64 */ -#define ____cacheline_internodealigned_in_smp \ - __attribute__((__aligned__(1 << 6))) - -#define LOCK_PREFIX "lock ; " - -#if 0 /* duplicate with arch_atomic.h */ - -/* - * Atomic data structure, initialization, and access. - */ - -typedef struct { volatile int counter; } atomic_t; - -#define ATOMIC_INIT(i) { (i) } - -#define atomic_read(v) ((v)->counter) -#define atomic_set(v, i) (((v)->counter) = (i)) - -/* - * Atomic operations. - */ - -/** - * atomic_add - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v. - */ -static __inline__ void atomic_add(int i, atomic_t *v) -{ - __asm__ __volatile__( - LOCK_PREFIX "addl %1,%0" - :"+m" (v->counter) - :"ir" (i)); -} - -/** - * atomic_sub - subtract the atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v. - */ -static __inline__ void atomic_sub(int i, atomic_t *v) -{ - __asm__ __volatile__( - LOCK_PREFIX "subl %1,%0" - :"+m" (v->counter) - :"ir" (i)); -} - -/** - * atomic_sub_and_test - subtract value from variable and test result - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v and returns - * true if the result is zero, or false for all - * other cases. - */ -static __inline__ int atomic_sub_and_test(int i, atomic_t *v) -{ - unsigned char c; - - __asm__ __volatile__( - LOCK_PREFIX "subl %2,%0; sete %1" - :"+m" (v->counter), "=qm" (c) - :"ir" (i) : "memory"); - return c; -} - -/** - * atomic_inc - increment atomic variable - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1. - */ -static __inline__ void atomic_inc(atomic_t *v) -{ - __asm__ __volatile__( - LOCK_PREFIX "incl %0" - :"+m" (v->counter)); -} - -/** - * atomic_dec - decrement atomic variable - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1. - */ -static __inline__ void atomic_dec(atomic_t *v) -{ - __asm__ __volatile__( - LOCK_PREFIX "decl %0" - :"+m" (v->counter)); -} - -/** - * atomic_dec_and_test - decrement and test - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1 and - * returns true if the result is 0, or false for all other - * cases. - */ -static __inline__ int atomic_dec_and_test(atomic_t *v) -{ - unsigned char c; - - __asm__ __volatile__( - LOCK_PREFIX "decl %0; sete %1" - :"+m" (v->counter), "=qm" (c) - : : "memory"); - return c != 0; -} - -/** - * atomic_inc_and_test - increment and test - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1 - * and returns true if the result is zero, or false for all - * other cases. - */ -static __inline__ int atomic_inc_and_test(atomic_t *v) -{ - unsigned char c; - - __asm__ __volatile__( - LOCK_PREFIX "incl %0; sete %1" - :"+m" (v->counter), "=qm" (c) - : : "memory"); - return c != 0; -} - -/** - * atomic_add_negative - add and test if negative - * @v: pointer of type atomic_t - * @i: integer value to add - * - * Atomically adds @i to @v and returns true - * if the result is negative, or false when - * result is greater than or equal to zero. - */ -static __inline__ int atomic_add_negative(int i, atomic_t *v) -{ - unsigned char c; - - __asm__ __volatile__( - LOCK_PREFIX "addl %2,%0; sets %1" - :"+m" (v->counter), "=qm" (c) - :"ir" (i) : "memory"); - return c; -} - -/** - * atomic_add_return - add and return - * @v: pointer of type atomic_t - * @i: integer value to add - * - * Atomically adds @i to @v and returns @i + @v - */ -static __inline__ int atomic_add_return(int i, atomic_t *v) -{ - int __i; - - __i = i; - __asm__ __volatile__( - LOCK_PREFIX "xaddl %0, %1;" - :"=r"(i) - :"m"(v->counter), "0"(i)); - return i + __i; -} - -static __inline__ int atomic_sub_return(int i, atomic_t *v) -{ - return atomic_add_return(-i,v); -} - -static inline unsigned int -cmpxchg(volatile long *ptr, long oldval, long newval) -{ - unsigned long retval; - - asm("# cmpxchg\n" - "lock; cmpxchgl %4,(%2)\n" - "# end atomic_cmpxchg4" - : "=a" (retval), "=m" (*ptr) - : "r" (ptr), "0" (oldval), "r" (newval), "m" (*ptr) - : "cc"); - return (retval); -} - -#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new)) -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) - -/** - * atomic_add_unless - add unless the number is a given value - * @v: pointer of type atomic_t - * @a: the amount to add to v... - * @u: ...unless v is equal to u. - * - * Atomically adds @a to @v, so long as it was not @u. - * Returns non-zero if @v was not @u, and zero otherwise. - */ -#define atomic_add_unless(v, a, u) \ -({ \ - int c, old; \ - c = atomic_read(v); \ - for (;;) { \ - if (unlikely(c == (u))) \ - break; \ - old = atomic_cmpxchg((v), c, c + (a)); \ - if (likely(old == c)) \ - break; \ - c = old; \ - } \ - c != (u); \ -}) -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) - -#define atomic_inc_return(v) (atomic_add_return(1,v)) -#define atomic_dec_return(v) (atomic_sub_return(1,v)) - -/* These are x86-specific, used by some header files */ -#define atomic_clear_mask(mask, addr) \ -__asm__ __volatile__(LOCK_PREFIX "andl %0,%1" \ -: : "r" (~(mask)),"m" (*addr) : "memory") - -#define atomic_set_mask(mask, addr) \ -__asm__ __volatile__(LOCK_PREFIX "orl %0,%1" \ -: : "r" (mask),"m" (*(addr)) : "memory") - -/* Atomic operations are already serializing on x86 */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - -#endif //0 - -/* - * api_pthreads.h: API mapping to pthreads environment. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. However, please note that much - * of the code in this file derives from the Linux kernel, and that such - * code may not be available except under GPLv2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (c) 2006 Paul E. McKenney, IBM. - */ - -#include -#include -#include -#include -#include -#define __USE_GNU -#include -#include -#include -/* #include "atomic.h" */ - -/* - * Compiler magic. - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -/* - * Default machine parameters. - */ - -#ifndef CACHE_LINE_SIZE -/* #define CACHE_LINE_SIZE 128 */ -#endif /* #ifndef CACHE_LINE_SIZE */ - -/* - * Exclusive locking primitives. - */ - -typedef pthread_mutex_t spinlock_t; - -#define DEFINE_SPINLOCK(lock) spinlock_t lock = PTHREAD_MUTEX_INITIALIZER; -#define __SPIN_LOCK_UNLOCKED(lockp) PTHREAD_MUTEX_INITIALIZER - -static void spin_lock_init(spinlock_t *sp) -{ - if (pthread_mutex_init(sp, NULL) != 0) { - perror("spin_lock_init:pthread_mutex_init"); - exit(-1); - } -} - -static void spin_lock(spinlock_t *sp) -{ - if (pthread_mutex_lock(sp) != 0) { - perror("spin_lock:pthread_mutex_lock"); - exit(-1); - } -} - -static void spin_unlock(spinlock_t *sp) -{ - if (pthread_mutex_unlock(sp) != 0) { - perror("spin_unlock:pthread_mutex_unlock"); - exit(-1); - } -} - -#define spin_lock_irqsave(l, f) do { f = 1; spin_lock(l); } while (0) -#define spin_unlock_irqrestore(l, f) do { f = 0; spin_unlock(l); } while (0) - -/* - * Thread creation/destruction primitives. - */ - -typedef pthread_t thread_id_t; - -#define NR_THREADS 128 - -#define __THREAD_ID_MAP_EMPTY 0 -#define __THREAD_ID_MAP_WAITING 1 -thread_id_t __thread_id_map[NR_THREADS]; -spinlock_t __thread_id_map_mutex; - -#define for_each_thread(t) \ - for (t = 0; t < NR_THREADS; t++) - -#define for_each_running_thread(t) \ - for (t = 0; t < NR_THREADS; t++) \ - if ((__thread_id_map[t] != __THREAD_ID_MAP_EMPTY) && \ - (__thread_id_map[t] != __THREAD_ID_MAP_WAITING)) - -pthread_key_t thread_id_key; - -static int __smp_thread_id(void) -{ - int i; - thread_id_t tid = pthread_self(); - - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == tid) { - long v = i + 1; /* must be non-NULL. */ - - if (pthread_setspecific(thread_id_key, (void *)v) != 0) { - perror("pthread_setspecific"); - exit(-1); - } - return i; - } - } - spin_lock(&__thread_id_map_mutex); - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == tid) - spin_unlock(&__thread_id_map_mutex); - return i; - } - spin_unlock(&__thread_id_map_mutex); - fprintf(stderr, "smp_thread_id: Rogue thread, id: %d(%#x)\n", - (int)tid, (int)tid); - exit(-1); -} - -static int smp_thread_id(void) -{ - void *id; - - id = pthread_getspecific(thread_id_key); - if (id == NULL) - return __smp_thread_id(); - return (long)(id - 1); -} - -static thread_id_t create_thread(void *(*func)(void *), void *arg) -{ - thread_id_t tid; - int i; - - spin_lock(&__thread_id_map_mutex); - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == __THREAD_ID_MAP_EMPTY) - break; - } - if (i >= NR_THREADS) { - spin_unlock(&__thread_id_map_mutex); - fprintf(stderr, "Thread limit of %d exceeded!\n", NR_THREADS); - exit(-1); - } - __thread_id_map[i] = __THREAD_ID_MAP_WAITING; - spin_unlock(&__thread_id_map_mutex); - if (pthread_create(&tid, NULL, func, arg) != 0) { - perror("create_thread:pthread_create"); - exit(-1); - } - __thread_id_map[i] = tid; - return tid; -} - -static void *wait_thread(thread_id_t tid) -{ - int i; - void *vp; - - for (i = 0; i < NR_THREADS; i++) { - if (__thread_id_map[i] == tid) - break; - } - if (i >= NR_THREADS){ - fprintf(stderr, "wait_thread: bad tid = %d(%#x)\n", - (int)tid, (int)tid); - exit(-1); - } - if (pthread_join(tid, &vp) != 0) { - perror("wait_thread:pthread_join"); - exit(-1); - } - __thread_id_map[i] = __THREAD_ID_MAP_EMPTY; - return vp; -} - -static void wait_all_threads(void) -{ - int i; - thread_id_t tid; - - for (i = 1; i < NR_THREADS; i++) { - tid = __thread_id_map[i]; - if (tid != __THREAD_ID_MAP_EMPTY && - tid != __THREAD_ID_MAP_WAITING) - (void)wait_thread(tid); - } -} - -static void run_on(int cpu) -{ - cpu_set_t mask; - - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - sched_setaffinity(0, sizeof(mask), &mask); -} - -/* - * timekeeping -- very crude -- should use MONOTONIC... - */ - -long long get_microseconds(void) -{ - struct timeval tv; - - if (gettimeofday(&tv, NULL) != 0) - abort(); - return ((long long)tv.tv_sec) * 1000000LL + (long long)tv.tv_usec; -} - -/* - * Per-thread variables. - */ - -#define DEFINE_PER_THREAD(type, name) \ - struct { \ - __typeof__(type) v \ - __attribute__((__aligned__(CACHE_LINE_SIZE))); \ - } __per_thread_##name[NR_THREADS]; -#define DECLARE_PER_THREAD(type, name) extern DEFINE_PER_THREAD(type, name) - -#define per_thread(name, thread) __per_thread_##name[thread].v -#define __get_thread_var(name) per_thread(name, smp_thread_id()) - -#define init_per_thread(name, v) \ - do { \ - int __i_p_t_i; \ - for (__i_p_t_i = 0; __i_p_t_i < NR_THREADS; __i_p_t_i++) \ - per_thread(name, __i_p_t_i) = v; \ - } while (0) - -/* - * CPU traversal primitives. - */ - -#ifndef NR_CPUS -#define NR_CPUS 16 -#endif /* #ifndef NR_CPUS */ - -#define for_each_possible_cpu(cpu) \ - for (cpu = 0; cpu < NR_CPUS; cpu++) -#define for_each_online_cpu(cpu) \ - for (cpu = 0; cpu < NR_CPUS; cpu++) - -/* - * Per-CPU variables. - */ - -#define DEFINE_PER_CPU(type, name) \ - struct { \ - __typeof__(type) v \ - __attribute__((__aligned__(CACHE_LINE_SIZE))); \ - } __per_cpu_##name[NR_CPUS] -#define DECLARE_PER_CPU(type, name) extern DEFINE_PER_CPU(type, name) - -DEFINE_PER_THREAD(int, smp_processor_id); - -#define per_cpu(name, thread) __per_cpu_##name[thread].v -#define __get_cpu_var(name) per_cpu(name, smp_processor_id()) - -#define init_per_cpu(name, v) \ - do { \ - int __i_p_c_i; \ - for (__i_p_c_i = 0; __i_p_c_i < NR_CPUS; __i_p_c_i++) \ - per_cpu(name, __i_p_c_i) = v; \ - } while (0) - -/* - * CPU state checking (crowbarred). - */ - -#define idle_cpu(cpu) 0 -#define in_softirq() 1 -#define hardirq_count() 0 -#define PREEMPT_SHIFT 0 -#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) -#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) -#define PREEMPT_BITS 8 -#define SOFTIRQ_BITS 8 - -/* - * CPU hotplug. - */ - -struct notifier_block { - int (*notifier_call)(struct notifier_block *, unsigned long, void *); - struct notifier_block *next; - int priority; -}; - -#define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */ -#define CPU_UP_PREPARE 0x0003 /* CPU (unsigned)v coming up */ -#define CPU_UP_CANCELED 0x0004 /* CPU (unsigned)v NOT coming up */ -#define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */ -#define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */ -#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */ -#define CPU_DYING 0x0008 /* CPU (unsigned)v not running any task, - * not handling interrupts, soon dead */ -#define CPU_POST_DEAD 0x0009 /* CPU (unsigned)v dead, cpu_hotplug - * lock is dropped */ - -/* Used for CPU hotplug events occuring while tasks are frozen due to a suspend - * operation in progress - */ -#define CPU_TASKS_FROZEN 0x0010 - -#define CPU_ONLINE_FROZEN (CPU_ONLINE | CPU_TASKS_FROZEN) -#define CPU_UP_PREPARE_FROZEN (CPU_UP_PREPARE | CPU_TASKS_FROZEN) -#define CPU_UP_CANCELED_FROZEN (CPU_UP_CANCELED | CPU_TASKS_FROZEN) -#define CPU_DOWN_PREPARE_FROZEN (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN) -#define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN) -#define CPU_DEAD_FROZEN (CPU_DEAD | CPU_TASKS_FROZEN) -#define CPU_DYING_FROZEN (CPU_DYING | CPU_TASKS_FROZEN) - -/* Hibernation and suspend events */ -#define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */ -#define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */ -#define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */ -#define PM_POST_SUSPEND 0x0004 /* Suspend finished */ -#define PM_RESTORE_PREPARE 0x0005 /* Going to restore a saved image */ -#define PM_POST_RESTORE 0x0006 /* Restore failed */ - -#define NOTIFY_DONE 0x0000 /* Don't care */ -#define NOTIFY_OK 0x0001 /* Suits me */ -#define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ -#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) - /* Bad/Veto action */ -/* - * Clean way to return from the notifier and stop further calls. - */ -#define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK) - -/* - * Bug checks. - */ - -#define BUG_ON(c) do { if (!(c)) abort(); } while (0) - -/* - * Initialization -- Must be called before calling any primitives. - */ - -static void smp_init(void) -{ - int i; - - spin_lock_init(&__thread_id_map_mutex); - __thread_id_map[0] = pthread_self(); - for (i = 1; i < NR_THREADS; i++) - __thread_id_map[i] = __THREAD_ID_MAP_EMPTY; - init_per_thread(smp_processor_id, 0); - if (pthread_key_create(&thread_id_key, NULL) != 0) { - perror("pthread_key_create"); - exit(-1); - } -} - -/* Taken from the Linux kernel source tree, so GPLv2-only!!! */ - -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#if 0 - -/* - * 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. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -#ifndef CONFIG_DEBUG_LIST -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} -#else -extern void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next); -#endif - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = 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. - */ -#ifndef CONFIG_DEBUG_LIST -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} -#else -extern void list_del(struct list_head *entry); -#endif - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -/** - * list_is_singular - tests whether a list has just one entry. - * @head: the list to test. - */ -static inline int list_is_singular(const struct list_head *head) -{ - return !list_empty(head) && (head->next == head->prev); -} - -static inline void __list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) -{ - struct list_head *new_first = entry->next; - list->next = head->next; - list->next->prev = list; - list->prev = entry; - entry->next = list; - head->next = new_first; - new_first->prev = head; -} - -/** - * list_cut_position - cut a list into two - * @list: a new list to add all removed entries - * @head: a list with entries - * @entry: an entry within head, could be the head itself - * and if so we won't cut the list - * - * This helper moves the initial part of @head, up to and - * including @entry, from @head to @list. You should - * pass on @entry an element you know is on @head. @list - * should be an empty list or a list you do not care about - * losing its data. - * - */ -static inline void list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) -{ - if (list_empty(head)) - return; - if (list_is_singular(head) && - (head->next != entry && head != entry)) - return; - if (entry == head) - INIT_LIST_HEAD(list); - else - __list_cut_position(list, head, entry); -} - -static inline void __list_splice(const struct list_head *list, - struct list_head *prev, - struct list_head *next) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - - first->prev = prev; - prev->next = first; - - last->next = next; - next->prev = last; -} - -/** - * list_splice - join two lists, this is designed for stacks - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(const struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head, head->next); -} - -/** - * list_splice_tail - join two lists, each list being a queue - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice_tail(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head->prev, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head, head->next); - INIT_LIST_HEAD(list); - } -} - -/** - * list_splice_tail_init - join two lists and reinitialise the emptied list - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * Each of the lists is a queue. - * The list at @list is reinitialised - */ -static inline void list_splice_tail_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head->prev, head); - INIT_LIST_HEAD(list); - } -} - -/** - * 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. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; prefetch(pos->next), pos != (head); \ - pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - prefetch(pos->prev), pos != (head); \ - pos = n, n = pos->prev) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -#endif //0 - -/* - * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -static inline void INIT_HLIST_NODE(struct hlist_node *h) -{ - h->next = NULL; - h->pprev = NULL; -} - -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; -} - -static inline void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; -} - -static inline void hlist_del_init(struct hlist_node *n) -{ - if (!hlist_unhashed(n)) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - -/* next must be != NULL */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; -} - -static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) -{ - next->next = n->next; - n->next = next; - next->pprev = &n->next; - - if(next->next) - next->next->pprev = &next->next; -} - -/* - * Move a list from one list head to another. Fixup the pprev - * reference of the first entry if it exists. - */ -static inline void hlist_move_list(struct hlist_head *old, - struct hlist_head *new) -{ - new->first = old->first; - if (new->first) - new->first->pprev = &new->first; - old->first = NULL; -} - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) - -/** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) - -#endif diff --git a/tests/rcutorture.h b/tests/rcutorture.h deleted file mode 100644 index 712d59d..0000000 --- a/tests/rcutorture.h +++ /dev/null @@ -1,417 +0,0 @@ -/* - * rcutorture.h: simple user-level performance/stress test of RCU. - * - * Usage: - * ./rcu rperf [ ] - * Run a read-side performance test with the specified - * number of readers spaced by . - * Thus "./rcu 16 rperf 2" would run 16 readers on even-numbered - * CPUs from 0 to 30. - * ./rcu uperf [ ] - * Run an update-side performance test with the specified - * number of updaters and specified CPU spacing. - * ./rcu perf [ ] - * Run a combined read/update performance test with the specified - * number of readers and one updater and specified CPU spacing. - * The readers run on the low-numbered CPUs and the updater - * of the highest-numbered CPU. - * - * The above tests produce output as follows: - * - * n_reads: 46008000 n_updates: 146026 nreaders: 2 nupdaters: 1 duration: 1 - * ns/read: 43.4707 ns/update: 6848.1 - * - * The first line lists the total number of RCU reads and updates executed - * during the test, the number of reader threads, the number of updater - * threads, and the duration of the test in seconds. The second line - * lists the average duration of each type of operation in nanoseconds, - * or "nan" if the corresponding type of operation was not performed. - * - * ./rcu stress - * Run a stress test with the specified number of readers and - * one updater. None of the threads are affinitied to any - * particular CPU. - * - * This test produces output as follows: - * - * n_reads: 114633217 n_updates: 3903415 n_mberror: 0 - * rcu_stress_count: 114618391 14826 0 0 0 0 0 0 0 0 0 - * - * The first line lists the number of RCU read and update operations - * executed, followed by the number of memory-ordering violations - * (which will be zero in a correct RCU implementation). The second - * line lists the number of readers observing progressively more stale - * data. A correct RCU implementation will have all but the first two - * numbers non-zero. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (c) 2008 Paul E. McKenney, IBM Corporation. - */ - -/* - * Test variables. - */ - -DEFINE_PER_THREAD(long long, n_reads_pt); -DEFINE_PER_THREAD(long long, n_updates_pt); - -long long n_reads = 0LL; -long n_updates = 0L; -int nthreadsrunning; -char argsbuf[64]; - -#define GOFLAG_INIT 0 -#define GOFLAG_RUN 1 -#define GOFLAG_STOP 2 - -int goflag __attribute__((__aligned__(CACHE_LINE_SIZE))) = GOFLAG_INIT; - -#define RCU_READ_RUN 1000 - -//MD -#define RCU_READ_NESTABLE - -#ifdef RCU_READ_NESTABLE -#define rcu_read_lock_nest() rcu_read_lock() -#define rcu_read_unlock_nest() rcu_read_unlock() -#else /* #ifdef RCU_READ_NESTABLE */ -#define rcu_read_lock_nest() -#define rcu_read_unlock_nest() -#endif /* #else #ifdef RCU_READ_NESTABLE */ - -#ifndef mark_rcu_quiescent_state -#define mark_rcu_quiescent_state() do ; while (0) -#endif /* #ifdef mark_rcu_quiescent_state */ - -#ifndef put_thread_offline -#define put_thread_offline() do ; while (0) -#define put_thread_online() do ; while (0) -#define put_thread_online_delay() do ; while (0) -#else /* #ifndef put_thread_offline */ -#define put_thread_online_delay() synchronize_rcu() -#endif /* #else #ifndef put_thread_offline */ - -/* - * Performance test. - */ - -void *rcu_read_perf_test(void *arg) -{ - int i; - int me = (long)arg; - long long n_reads_local = 0; - - rcu_register_thread(); - run_on(me); - uatomic_inc(&nthreadsrunning); - while (goflag == GOFLAG_INIT) - poll(NULL, 0, 1); - mark_rcu_quiescent_state(); - while (goflag == GOFLAG_RUN) { - for (i = 0; i < RCU_READ_RUN; i++) { - rcu_read_lock(); - /* rcu_read_lock_nest(); */ - /* rcu_read_unlock_nest(); */ - rcu_read_unlock(); - } - n_reads_local += RCU_READ_RUN; - mark_rcu_quiescent_state(); - } - __get_thread_var(n_reads_pt) += n_reads_local; - put_thread_offline(); - rcu_unregister_thread(); - - return (NULL); -} - -void *rcu_update_perf_test(void *arg) -{ - long long n_updates_local = 0; - - uatomic_inc(&nthreadsrunning); - while (goflag == GOFLAG_INIT) - poll(NULL, 0, 1); - while (goflag == GOFLAG_RUN) { - synchronize_rcu(); - n_updates_local++; - } - __get_thread_var(n_updates_pt) += n_updates_local; - return NULL; -} - -void perftestinit(void) -{ - init_per_thread(n_reads_pt, 0LL); - init_per_thread(n_updates_pt, 0LL); - uatomic_set(&nthreadsrunning, 0); -} - -void perftestrun(int nthreads, int nreaders, int nupdaters) -{ - int t; - int duration = 1; - - smp_mb(); - while (uatomic_read(&nthreadsrunning) < nthreads) - poll(NULL, 0, 1); - goflag = GOFLAG_RUN; - smp_mb(); - sleep(duration); - smp_mb(); - goflag = GOFLAG_STOP; - smp_mb(); - wait_all_threads(); - for_each_thread(t) { - n_reads += per_thread(n_reads_pt, t); - n_updates += per_thread(n_updates_pt, t); - } - printf("n_reads: %lld n_updates: %ld nreaders: %d nupdaters: %d duration: %d\n", - n_reads, n_updates, nreaders, nupdaters, duration); - printf("ns/read: %g ns/update: %g\n", - ((duration * 1000*1000*1000.*(double)nreaders) / - (double)n_reads), - ((duration * 1000*1000*1000.*(double)nupdaters) / - (double)n_updates)); - exit(0); -} - -void perftest(int nreaders, int cpustride) -{ - int i; - long arg; - - perftestinit(); - for (i = 0; i < nreaders; i++) { - arg = (long)(i * cpustride); - create_thread(rcu_read_perf_test, (void *)arg); - } - arg = (long)(i * cpustride); - create_thread(rcu_update_perf_test, (void *)arg); - perftestrun(i + 1, nreaders, 1); -} - -void rperftest(int nreaders, int cpustride) -{ - int i; - long arg; - - perftestinit(); - init_per_thread(n_reads_pt, 0LL); - for (i = 0; i < nreaders; i++) { - arg = (long)(i * cpustride); - create_thread(rcu_read_perf_test, (void *)arg); - } - perftestrun(i, nreaders, 0); -} - -void uperftest(int nupdaters, int cpustride) -{ - int i; - long arg; - - perftestinit(); - init_per_thread(n_reads_pt, 0LL); - for (i = 0; i < nupdaters; i++) { - arg = (long)(i * cpustride); - create_thread(rcu_update_perf_test, (void *)arg); - } - perftestrun(i, 0, nupdaters); -} - -/* - * Stress test. - */ - -#define RCU_STRESS_PIPE_LEN 10 - -struct rcu_stress { - int pipe_count; - int mbtest; -}; - -struct rcu_stress rcu_stress_array[RCU_STRESS_PIPE_LEN] = { { 0 } }; -struct rcu_stress *rcu_stress_current; -int rcu_stress_idx = 0; - -int n_mberror = 0; -DEFINE_PER_THREAD(long long [RCU_STRESS_PIPE_LEN + 1], rcu_stress_count); - -int garbage = 0; - -void *rcu_read_stress_test(void *arg) -{ - int i; - int itercnt = 0; - struct rcu_stress *p; - int pc; - - rcu_register_thread(); - while (goflag == GOFLAG_INIT) - poll(NULL, 0, 1); - mark_rcu_quiescent_state(); - while (goflag == GOFLAG_RUN) { - rcu_read_lock(); - p = rcu_dereference(rcu_stress_current); - if (p->mbtest == 0) - n_mberror++; - rcu_read_lock_nest(); - for (i = 0; i < 100; i++) - garbage++; - rcu_read_unlock_nest(); - pc = p->pipe_count; - rcu_read_unlock(); - if ((pc > RCU_STRESS_PIPE_LEN) || (pc < 0)) - pc = RCU_STRESS_PIPE_LEN; - __get_thread_var(rcu_stress_count)[pc]++; - __get_thread_var(n_reads_pt)++; - mark_rcu_quiescent_state(); - if ((++itercnt % 0x1000) == 0) { - put_thread_offline(); - put_thread_online_delay(); - put_thread_online(); - } - } - put_thread_offline(); - rcu_unregister_thread(); - - return (NULL); -} - -void *rcu_update_stress_test(void *arg) -{ - int i; - struct rcu_stress *p; - - while (goflag == GOFLAG_INIT) - poll(NULL, 0, 1); - while (goflag == GOFLAG_RUN) { - i = rcu_stress_idx + 1; - if (i >= RCU_STRESS_PIPE_LEN) - i = 0; - p = &rcu_stress_array[i]; - p->mbtest = 0; - smp_mb(); - p->pipe_count = 0; - p->mbtest = 1; - rcu_assign_pointer(rcu_stress_current, p); - rcu_stress_idx = i; - for (i = 0; i < RCU_STRESS_PIPE_LEN; i++) - if (i != rcu_stress_idx) - rcu_stress_array[i].pipe_count++; - synchronize_rcu(); - n_updates++; - } - return NULL; -} - -void *rcu_fake_update_stress_test(void *arg) -{ - while (goflag == GOFLAG_INIT) - poll(NULL, 0, 1); - while (goflag == GOFLAG_RUN) { - synchronize_rcu(); - poll(NULL, 0, 1); - } - return NULL; -} - -void stresstest(int nreaders) -{ - int i; - int t; - long long *p; - long long sum; - - init_per_thread(n_reads_pt, 0LL); - for_each_thread(t) { - p = &per_thread(rcu_stress_count,t)[0]; - for (i = 0; i <= RCU_STRESS_PIPE_LEN; i++) - p[i] = 0LL; - } - rcu_stress_current = &rcu_stress_array[0]; - rcu_stress_current->pipe_count = 0; - rcu_stress_current->mbtest = 1; - for (i = 0; i < nreaders; i++) - create_thread(rcu_read_stress_test, NULL); - create_thread(rcu_update_stress_test, NULL); - for (i = 0; i < 5; i++) - create_thread(rcu_fake_update_stress_test, NULL); - smp_mb(); - goflag = GOFLAG_RUN; - smp_mb(); - sleep(10); - smp_mb(); - goflag = GOFLAG_STOP; - smp_mb(); - wait_all_threads(); - for_each_thread(t) - n_reads += per_thread(n_reads_pt, t); - printf("n_reads: %lld n_updates: %ld n_mberror: %d\n", - n_reads, n_updates, n_mberror); - printf("rcu_stress_count:"); - for (i = 0; i <= RCU_STRESS_PIPE_LEN; i++) { - sum = 0LL; - for_each_thread(t) { - sum += per_thread(rcu_stress_count, t)[i]; - } - printf(" %lld", sum); - } - printf("\n"); - exit(0); -} - -/* - * Mainprogram. - */ - -void usage(int argc, char *argv[]) -{ - fprintf(stderr, "Usage: %s [nreaders [ perf | stress ] ]\n", argv[0]); - exit(-1); -} - -int main(int argc, char *argv[]) -{ - int nreaders = 1; - int cpustride = 1; - - smp_init(); - //rcu_init(); - -#ifdef DEBUG_YIELD - yield_active |= YIELD_READ; - yield_active |= YIELD_WRITE; -#endif - - if (argc > 1) { - nreaders = strtoul(argv[1], NULL, 0); - if (argc == 2) - perftest(nreaders, cpustride); - if (argc > 3) - cpustride = strtoul(argv[3], NULL, 0); - if (strcmp(argv[2], "perf") == 0) - perftest(nreaders, cpustride); - else if (strcmp(argv[2], "rperf") == 0) - rperftest(nreaders, cpustride); - else if (strcmp(argv[2], "uperf") == 0) - uperftest(nreaders, cpustride); - else if (strcmp(argv[2], "stress") == 0) - stresstest(nreaders); - usage(argc, argv); - } - perftest(nreaders, cpustride); - return 0; -} diff --git a/tests/runall.sh b/tests/runall.sh deleted file mode 100755 index e2b47dc..0000000 --- a/tests/runall.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/sh - -#run all tests - -#set to number of active CPUS -NUM_CPUS=8 - -#extra options, e.g. for setting affinity on even CPUs : -#EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done) - -#ppc64 striding, use with NUM_CPUS=8 - -#stride 1 -#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done) -#stride 2 -#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done) -#stride 4 -#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done) -#stride 8 -#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done) - -#Vary update fraction -#x: vary update fraction from 0 to 0.0001 - #fix number of readers and reader C.S. length, vary delay between updates -#y: ops/s - -rm -f runall.log -rm -fr runall.detail.log - - -echo Executing batch RCU test - -DURATION=10 -BATCH_ARRAY="1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 - 131072 262144" -NR_WRITERS=$((${NUM_CPUS} / 2)) - -rm -f batch-rcu.log - -NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS})) -for BATCH_SIZE in ${BATCH_ARRAY}; do - echo "./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log" >> runall.log - ./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log -done - -#setting gc each 32768. ** UPDATE FOR YOUR ARCHITECTURE BASED ON TEST ABOVE ** -EXTRA_OPTS+="-b 32768" - -echo Executing update fraction test - -DURATION=10 -WDELAY_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 - 65536 131072 262144 524288 1048576 2097152 4194304 8388608 - 16777216 33554432 67108864 134217728" -NR_WRITERS=$((${NUM_CPUS} / 2)) - -rm -f update-fraction.log - -NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS})) -for WDELAY in ${WDELAY_ARRAY}; do - echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log" >> runall.log - ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log -done - -#Test scalability : -# x: vary number of readers from 0 to num cpus -# y: ops/s -# 0 writer. - -echo Executing scalability test - -NR_WRITERS=0 -DURATION=10 - -rm -f scalability.log - -for NR_READERS in $(seq 1 ${NUM_CPUS}); do - echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log" >> runall.log - ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log -done - - -# x: Vary reader C.S. length from 0 to 100 us -# y: ops/s -# 8 readers -# 0 writers - -echo Executing reader C.S. length test - -NR_READERS=${NUM_CPUS} -NR_WRITERS=0 -DURATION=10 -#in loops. -READERCSLEN_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152" - -rm -f readercslen.log - -for READERCSLEN in ${READERCSLEN_ARRAY}; do - echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log" >> runall.log - ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log -done diff --git a/tests/runpaul-phase1.sh b/tests/runpaul-phase1.sh deleted file mode 100755 index d2c8649..0000000 --- a/tests/runpaul-phase1.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -#run all tests - -#set to number of active CPUS -NUM_CPUS=64 - -#extra options, e.g. for setting affinity on even CPUs : -EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done) - -#ppc64 striding, use with NUM_CPUS=8 - -#stride 1 -#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done) -#stride 2 -#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done) -#stride 4 -#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done) -#stride 8 -#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done) - -#Vary update fraction -#x: vary update fraction from 0 to 0.0001 - #fix number of readers and reader C.S. length, vary delay between updates -#y: ops/s - -rm -f runall.log -rm -fr runall.detail.log - - -echo Executing batch RCU test - -DURATION=10 -BATCH_ARRAY="1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 - 131072 262144" -NR_WRITERS=$((${NUM_CPUS} / 2)) - -rm -f batch-rcu.log - -NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS})) -for BATCH_SIZE in ${BATCH_ARRAY}; do - echo "./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log" >> runall.log - ./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log -done diff --git a/tests/runpaul-phase2.sh b/tests/runpaul-phase2.sh deleted file mode 100755 index 0f6bd91..0000000 --- a/tests/runpaul-phase2.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh - -#run all tests - -#set to number of active CPUS -NUM_CPUS=64 - -#extra options, e.g. for setting affinity on even CPUs : -EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done) - -#ppc64 striding, use with NUM_CPUS=8 - -#stride 1 -#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done) -#stride 2 -#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done) -#stride 4 -#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done) -#stride 8 -#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done) - -#Vary update fraction -#x: vary update fraction from 0 to 0.0001 - #fix number of readers and reader C.S. length, vary delay between updates -#y: ops/s - -rm -f runall.log -rm -fr runall.detail.log - -#setting gc each 32768. ** UPDATE FOR YOUR ARCHITECTURE BASED ON PHASE 1 RESULT ** -EXTRA_OPTS+="-b 32768" - -echo Executing update fraction test - -DURATION=10 -WDELAY_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 - 65536 131072 262144 524288 1048576 2097152 4194304 8388608 - 16777216 33554432 67108864 134217728" -NR_WRITERS=$((${NUM_CPUS} / 2)) - -rm -f update-fraction.log - -NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS})) -for WDELAY in ${WDELAY_ARRAY}; do - echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log" >> runall.log - ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log -done diff --git a/tests/runpaul-phase3.sh b/tests/runpaul-phase3.sh deleted file mode 100755 index 1956062..0000000 --- a/tests/runpaul-phase3.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh - -#run all tests - -#set to number of active CPUS -NUM_CPUS=64 - -#extra options, e.g. for setting affinity on even CPUs : -EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done) - -#ppc64 striding, use with NUM_CPUS=8 - -#stride 1 -#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done) -#stride 2 -#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done) -#stride 4 -#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done) -#stride 8 -#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done) - -#Vary update fraction -#x: vary update fraction from 0 to 0.0001 - #fix number of readers and reader C.S. length, vary delay between updates -#y: ops/s - -rm -f runall.log -rm -fr runall.detail.log - -#setting gc each 32768. ** UPDATE FOR YOUR ARCHITECTURE BASED ON PHASE 1 RESULT ** -EXTRA_OPTS+="-b 32768" - -#Test scalability : -# x: vary number of readers from 0 to num cpus -# y: ops/s -# 0 writer. - -echo Executing scalability test - -NR_WRITERS=0 -DURATION=10 - -rm -f scalability.log - -for NR_READERS in $(seq 1 ${NUM_CPUS}); do - echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log" >> runall.log - ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log -done - - diff --git a/tests/runpaul-phase4.sh b/tests/runpaul-phase4.sh deleted file mode 100755 index ede402c..0000000 --- a/tests/runpaul-phase4.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh - -#run all tests - -#set to number of active CPUS -export NUM_CPUS=8 - -#extra options, e.g. for setting affinity on even CPUs : -#EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done) - -#ppc64 striding, use with NUM_CPUS=8 - -rm -f *.log - -#stride 1 -export EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done) -sh subphase4.sh $* -mkdir ppc64-8cores-stride1 -mv *.log ppc64-8cores-stride1/ - - -#stride 2 -export EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done) -sh subphase4.sh $* -mkdir ppc64-8cores-stride2 -mv *.log ppc64-8cores-stride2/ - - -#stride 4 -export EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done) -sh subphase4.sh $* -mkdir ppc64-8cores-stride4 -mv *.log ppc64-8cores-stride4/ - - -#stride 8 -export EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done) -sh subphase4.sh $* -mkdir ppc64-8cores-stride8 -mv *.log ppc64-8cores-stride8/ diff --git a/tests/runpaul-phase5.sh b/tests/runpaul-phase5.sh deleted file mode 100644 index bb4bfe7..0000000 --- a/tests/runpaul-phase5.sh +++ /dev/null @@ -1,11 +0,0 @@ -# test run after write-size update - -sh runpaul-phase1.sh -mkdir runpaul-phase1 -mv *.log runpaul-phase1/ - -sh runpaul-phase2.sh -mkdir runpaul-phase2 -mv *.log runpaul-phase2/ - -sh runpaul-phase4.sh diff --git a/tests/runpaul-phase6.sh b/tests/runpaul-phase6.sh deleted file mode 100644 index 5f65072..0000000 --- a/tests/runpaul-phase6.sh +++ /dev/null @@ -1,7 +0,0 @@ -sh runpaul-phase1.sh -mkdir runpaul-phase1 -mv *.log runpaul-phase1/ - -sh runpaul-phase2.sh -mkdir runpaul-phase2 -mv *.log runpaul-phase2/ diff --git a/tests/runtests-batch.sh b/tests/runtests-batch.sh deleted file mode 100755 index 67e019b..0000000 --- a/tests/runtests-batch.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -#for a in test_urcu_gc test_urcu_gc_mb test_qsbr_gc; do -for a in test_urcu_gc; do - echo "./${a} $*" | tee -a runall.detail.log - /usr/bin/time --append --output runall.detail.log ./${a} $* -done - diff --git a/tests/runtests.sh b/tests/runtests.sh deleted file mode 100755 index 981aef1..0000000 --- a/tests/runtests.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -for a in test_urcu_gc test_urcu_gc_mb test_urcu test_urcu_mb \ - test_urcu_lgc test_qsbr_lgc test_urcu_lgc_mb \ - test_qsbr test_qsbr_gc test_rwlock test_perthreadlock \ - test_mutex; do - echo "./${a} $*" | tee -a runall.detail.log - /usr/bin/time --append --output runall.detail.log ./${a} $* -done - diff --git a/tests/subphase4.sh b/tests/subphase4.sh deleted file mode 100755 index b69ffbf..0000000 --- a/tests/subphase4.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/sh - -#run all tests - -#set to number of active CPUS -#NUM_CPUS=8 - -#extra options, e.g. for setting affinity on even CPUs : -#EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done) - -#ppc64 striding, use with NUM_CPUS=8 - -#stride 1 -#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done) -#stride 2 -#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done) -#stride 4 -#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done) -#stride 8 -#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done) - -#Vary update fraction -#x: vary update fraction from 0 to 0.0001 - #fix number of readers and reader C.S. length, vary delay between updates -#y: ops/s - -rm -f runall.log -rm -fr runall.detail.log - - -echo Executing batch RCU test - -DURATION=10 -BATCH_ARRAY="1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 - 131072 262144" -NR_WRITERS=$((${NUM_CPUS} / 2)) - -rm -f batch-rcu.log - -NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS})) -for BATCH_SIZE in ${BATCH_ARRAY}; do - echo "./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log" >> runall.log - ./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log -done - -#setting gc each 4096. ** UPDATE FOR YOUR ARCHITECTURE BASED ON TEST ABOVE ** -EXTRA_OPTS+="-b 32768" - -echo Executing update fraction test - -DURATION=10 -WDELAY_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 - 65536 131072 262144 524288 1048576 2097152 4194304 8388608 - 16777216 33554432 67108864 134217728" -NR_WRITERS=$((${NUM_CPUS} / 2)) - -rm -f update-fraction.log - -NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS})) -for WDELAY in ${WDELAY_ARRAY}; do - echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log" >> runall.log - ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log -done - -#Test scalability : -# x: vary number of readers from 0 to num cpus -# y: ops/s -# 0 writer. - -echo Executing scalability test - -NR_WRITERS=0 -DURATION=10 - -rm -f scalability.log - -for NR_READERS in $(seq 1 ${NUM_CPUS}); do - echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log" >> runall.log - ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log -done - - -# x: Vary reader C.S. length from 0 to 100 us -# y: ops/s -# 8 readers -# 0 writers - -echo Executing reader C.S. length test - -NR_READERS=${NUM_CPUS} -NR_WRITERS=0 -DURATION=10 -#in loops. -READERCSLEN_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152" - -rm -f readercslen.log - -for READERCSLEN in ${READERCSLEN_ARRAY}; do - echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log" >> runall.log - ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log -done diff --git a/tests/test_looplen.c b/tests/test_looplen.c deleted file mode 100644 index 9e2ee2b..0000000 --- a/tests/test_looplen.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * test_looplen.c - * - * Userspace RCU library - test program - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#ifndef DYNAMIC_LINK_TEST -#define _LGPL_SOURCE -#else -#define debug_yield_read() -#endif -#include - -static inline void loop_sleep(unsigned long l) -{ - while(l-- != 0) - cpu_relax(); -} - -#define LOOPS 1048576 -#define TESTS 10 - -int main(int argc, char **argv) -{ - unsigned long i; - cycles_t time1, time2; - cycles_t time_tot = 0; - double cpl; - - for (i = 0; i < TESTS; i++) { - time1 = get_cycles(); - loop_sleep(LOOPS); - time2 = get_cycles(); - time_tot += time2 - time1; - } - cpl = ((double)time_tot) / (double)TESTS / (double)LOOPS; - - printf("CALIBRATION : %g cycles per loop\n", cpl); - printf("time_tot = %llu, LOOPS = %d, TESTS = %d\n", - time_tot, LOOPS, TESTS); - - return 0; -} diff --git a/tests/test_mutex.c b/tests/test_mutex.c deleted file mode 100644 index f2ef706..0000000 --- a/tests/test_mutex.c +++ /dev/null @@ -1,389 +0,0 @@ -/* - * test_urcu.c - * - * Userspace RCU library - test program - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* hardcoded number of CPUs */ -#define NR_CPUS 16384 - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#ifndef DYNAMIC_LINK_TEST -#define _LGPL_SOURCE -#else -#define debug_yield_read() -#endif -#include - -struct test_array { - int a; -}; - -static pthread_mutex_t lock; - -static volatile int test_go, test_stop; - -static unsigned long wdelay; - -static volatile struct test_array test_array = { 8 }; - -static unsigned long duration; - -/* read-side C.S. duration, in loops */ -static unsigned long rduration; - -static inline void loop_sleep(unsigned long l) -{ - while(l-- != 0) - cpu_relax(); -} - -static int verbose_mode; - -#define printf_verbose(fmt, args...) \ - do { \ - if (verbose_mode) \ - printf(fmt, args); \ - } while (0) - -static unsigned int cpu_affinities[NR_CPUS]; -static unsigned int next_aff = 0; -static int use_affinity = 0; - -pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void set_affinity(void) -{ - cpu_set_t mask; - int cpu; - int ret; - - if (!use_affinity) - return; - - ret = pthread_mutex_lock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } - cpu = cpu_affinities[next_aff++]; - ret = pthread_mutex_unlock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - sched_setaffinity(0, sizeof(mask), &mask); -} - -/* - * returns 0 if test should end. - */ -static int test_duration_write(void) -{ - return !test_stop; -} - -static int test_duration_read(void) -{ - return !test_stop; -} - -static unsigned long long __thread nr_writes; -static unsigned long long __thread nr_reads; - -static -unsigned long long __attribute__((aligned(CACHE_LINE_SIZE))) *tot_nr_writes; -static -unsigned long long __attribute__((aligned(CACHE_LINE_SIZE))) *tot_nr_reads; - -static unsigned int nr_readers; -static unsigned int nr_writers; - -pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; - -void rcu_copy_mutex_lock(void) -{ - int ret; - ret = pthread_mutex_lock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -} - -void rcu_copy_mutex_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -void *thr_reader(void *data) -{ - unsigned long tidx = (unsigned long)data; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - while (!test_go) - { - } - - for (;;) { - pthread_mutex_lock(&lock); - assert(test_array.a == 8); - if (unlikely(rduration)) - loop_sleep(rduration); - pthread_mutex_unlock(&lock); - nr_reads++; - if (unlikely(!test_duration_read())) - break; - } - - tot_nr_reads[tidx] = nr_reads; - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -void *thr_writer(void *data) -{ - unsigned long wtidx = (unsigned long)data; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { - pthread_mutex_lock(&lock); - test_array.a = 0; - test_array.a = 8; - pthread_mutex_unlock(&lock); - nr_writes++; - if (unlikely(!test_duration_write())) - break; - if (unlikely(wdelay)) - loop_sleep(wdelay); - } - - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - tot_nr_writes[wtidx] = nr_writes; - return ((void*)2); -} - -void show_usage(int argc, char **argv) -{ - printf("Usage : %s nr_readers nr_writers duration (s)", argv[0]); -#ifdef DEBUG_YIELD - printf(" [-r] [-w] (yield reader and/or writer)"); -#endif - printf(" [-d delay] (writer period (us))"); - printf(" [-c duration] (reader C.S. duration (in loops))"); - printf(" [-v] (verbose output)"); - printf(" [-a cpu#] [-a cpu#]... (affinity)"); - printf("\n"); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - unsigned long long *count_reader, *count_writer; - unsigned long long tot_reads = 0, tot_writes = 0; - int i, a; - - if (argc < 4) { - show_usage(argc, argv); - return -1; - } - smp_mb(); - - err = sscanf(argv[1], "%u", &nr_readers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[2], "%u", &nr_writers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[3], "%lu", &duration); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - for (i = 4; i < argc; i++) { - if (argv[i][0] != '-') - continue; - switch (argv[i][1]) { -#ifdef DEBUG_YIELD - case 'r': - yield_active |= YIELD_READ; - break; - case 'w': - yield_active |= YIELD_WRITE; - break; -#endif - case 'a': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - a = atoi(argv[++i]); - cpu_affinities[next_aff++] = a; - use_affinity = 1; - printf_verbose("Adding CPU %d affinity\n", a); - break; - case 'c': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - rduration = atol(argv[++i]); - break; - case 'd': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - wdelay = atol(argv[++i]); - break; - case 'v': - verbose_mode = 1; - break; - } - } - - printf_verbose("running test for %lu seconds, %u readers, %u writers.\n", - duration, nr_readers, nr_writers); - printf_verbose("Writer delay : %lu loops.\n", wdelay); - printf_verbose("Reader duration : %lu loops.\n", rduration); - printf_verbose("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - tid_reader = malloc(sizeof(*tid_reader) * nr_readers); - tid_writer = malloc(sizeof(*tid_writer) * nr_writers); - count_reader = malloc(sizeof(*count_reader) * nr_readers); - count_writer = malloc(sizeof(*count_writer) * nr_writers); - tot_nr_reads = malloc(sizeof(*tot_nr_reads) * nr_readers); - tot_nr_writes = malloc(sizeof(*tot_nr_writes) * nr_writers); - - next_aff = 0; - - for (i = 0; i < nr_readers; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - (void *)(long)i); - if (err != 0) - exit(1); - } - for (i = 0; i < nr_writers; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - (void *)(long)i); - if (err != 0) - exit(1); - } - - smp_mb(); - - test_go = 1; - - sleep(duration); - - test_stop = 1; - - for (i = 0; i < nr_readers; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_reads += tot_nr_reads[i]; - } - for (i = 0; i < nr_writers; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_writes += tot_nr_writes[i]; - } - - printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads, - tot_writes); - printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu " - "nr_writers %3u " - "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n", - argv[0], duration, nr_readers, rduration, - nr_writers, wdelay, tot_reads, tot_writes, - tot_reads + tot_writes); - - free(tid_reader); - free(tid_writer); - free(count_reader); - free(count_writer); - free(tot_nr_reads); - free(tot_nr_writes); - return 0; -} diff --git a/tests/test_perthreadlock.c b/tests/test_perthreadlock.c deleted file mode 100644 index 8e0800f..0000000 --- a/tests/test_perthreadlock.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * test_urcu.c - * - * Userspace RCU library - test program - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* hardcoded number of CPUs */ -#define NR_CPUS 16384 - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#ifndef DYNAMIC_LINK_TEST -#define _LGPL_SOURCE -#else -#define debug_yield_read() -#endif -#include - -struct test_array { - int a; -}; - -struct per_thread_lock { - pthread_mutex_t lock; -} __attribute__((aligned(CACHE_LINE_SIZE))); /* cache-line aligned */ - -static struct per_thread_lock *per_thread_lock; - -static volatile int test_go, test_stop; - -static unsigned long wdelay; - -static volatile struct test_array test_array = { 8 }; - -static unsigned long duration; - -/* read-side C.S. duration, in loops */ -static unsigned long rduration; - -static inline void loop_sleep(unsigned long l) -{ - while(l-- != 0) - cpu_relax(); -} - -static int verbose_mode; - -#define printf_verbose(fmt, args...) \ - do { \ - if (verbose_mode) \ - printf(fmt, args); \ - } while (0) - -static unsigned int cpu_affinities[NR_CPUS]; -static unsigned int next_aff = 0; -static int use_affinity = 0; - -pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void set_affinity(void) -{ - cpu_set_t mask; - int cpu; - int ret; - - if (!use_affinity) - return; - - ret = pthread_mutex_lock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } - cpu = cpu_affinities[next_aff++]; - ret = pthread_mutex_unlock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - sched_setaffinity(0, sizeof(mask), &mask); -} - -/* - * returns 0 if test should end. - */ -static int test_duration_write(void) -{ - return !test_stop; -} - -static int test_duration_read(void) -{ - return !test_stop; -} - -static unsigned long long __thread nr_writes; -static unsigned long long __thread nr_reads; - -static -unsigned long long __attribute__((aligned(CACHE_LINE_SIZE))) *tot_nr_writes; -static -unsigned long long __attribute__((aligned(CACHE_LINE_SIZE))) *tot_nr_reads; - -static unsigned int nr_readers; -static unsigned int nr_writers; - -pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; - -void rcu_copy_mutex_lock(void) -{ - int ret; - ret = pthread_mutex_lock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -} - -void rcu_copy_mutex_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -void *thr_reader(void *data) -{ - unsigned long tidx = (unsigned long)data; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - while (!test_go) - { - } - - for (;;) { - pthread_mutex_lock(&per_thread_lock[tidx].lock); - assert(test_array.a == 8); - if (unlikely(rduration)) - loop_sleep(rduration); - pthread_mutex_unlock(&per_thread_lock[tidx].lock); - nr_reads++; - if (unlikely(!test_duration_read())) - break; - } - - tot_nr_reads[tidx] = nr_reads; - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -void *thr_writer(void *data) -{ - unsigned long wtidx = (unsigned long)data; - long tidx; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { - for (tidx = 0; tidx < nr_readers; tidx++) { - pthread_mutex_lock(&per_thread_lock[tidx].lock); - } - test_array.a = 0; - test_array.a = 8; - for (tidx = (long)nr_readers - 1; tidx >= 0; tidx--) { - pthread_mutex_unlock(&per_thread_lock[tidx].lock); - } - nr_writes++; - if (unlikely(!test_duration_write())) - break; - if (unlikely(wdelay)) - loop_sleep(wdelay); - } - - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - tot_nr_writes[wtidx] = nr_writes; - return ((void*)2); -} - -void show_usage(int argc, char **argv) -{ - printf("Usage : %s nr_readers nr_writers duration (s)", argv[0]); -#ifdef DEBUG_YIELD - printf(" [-r] [-w] (yield reader and/or writer)"); -#endif - printf(" [-d delay] (writer period (us))"); - printf(" [-c duration] (reader C.S. duration (in loops))"); - printf(" [-v] (verbose output)"); - printf(" [-a cpu#] [-a cpu#]... (affinity)"); - printf("\n"); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - unsigned long long *count_reader, *count_writer; - unsigned long long tot_reads = 0, tot_writes = 0; - int i, a; - - if (argc < 4) { - show_usage(argc, argv); - return -1; - } - smp_mb(); - - err = sscanf(argv[1], "%u", &nr_readers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[2], "%u", &nr_writers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[3], "%lu", &duration); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - for (i = 4; i < argc; i++) { - if (argv[i][0] != '-') - continue; - switch (argv[i][1]) { -#ifdef DEBUG_YIELD - case 'r': - yield_active |= YIELD_READ; - break; - case 'w': - yield_active |= YIELD_WRITE; - break; -#endif - case 'a': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - a = atoi(argv[++i]); - cpu_affinities[next_aff++] = a; - use_affinity = 1; - printf_verbose("Adding CPU %d affinity\n", a); - break; - case 'c': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - rduration = atol(argv[++i]); - break; - case 'd': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - wdelay = atol(argv[++i]); - break; - case 'v': - verbose_mode = 1; - break; - } - } - - printf_verbose("running test for %lu seconds, %u readers, %u writers.\n", - duration, nr_readers, nr_writers); - printf_verbose("Writer delay : %lu loops.\n", wdelay); - printf_verbose("Reader duration : %lu loops.\n", rduration); - printf_verbose("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - tid_reader = malloc(sizeof(*tid_reader) * nr_readers); - tid_writer = malloc(sizeof(*tid_writer) * nr_writers); - count_reader = malloc(sizeof(*count_reader) * nr_readers); - count_writer = malloc(sizeof(*count_writer) * nr_writers); - tot_nr_reads = malloc(sizeof(*tot_nr_reads) * nr_readers); - tot_nr_writes = malloc(sizeof(*tot_nr_writes) * nr_writers); - per_thread_lock = malloc(sizeof(*per_thread_lock) * nr_readers); - - next_aff = 0; - - for (i = 0; i < nr_readers; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - (void *)(long)i); - if (err != 0) - exit(1); - } - for (i = 0; i < nr_writers; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - (void *)(long)i); - if (err != 0) - exit(1); - } - - smp_mb(); - - test_go = 1; - - sleep(duration); - - test_stop = 1; - - for (i = 0; i < nr_readers; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_reads += tot_nr_reads[i]; - } - for (i = 0; i < nr_writers; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_writes += tot_nr_writes[i]; - } - - printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads, - tot_writes); - printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu " - "nr_writers %3u " - "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n", - argv[0], duration, nr_readers, rduration, - nr_writers, wdelay, tot_reads, tot_writes, - tot_reads + tot_writes); - - free(tid_reader); - free(tid_writer); - free(count_reader); - free(count_writer); - free(tot_nr_reads); - free(tot_nr_writes); - free(per_thread_lock); - return 0; -} diff --git a/tests/test_perthreadlock_timing.c b/tests/test_perthreadlock_timing.c deleted file mode 100644 index 9761f5d..0000000 --- a/tests/test_perthreadlock_timing.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * test_perthreadloc_timing.c - * - * Per thread locks - test program - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#include - -struct test_array { - int a; -}; - -static struct test_array test_array = { 8 }; - -struct per_thread_lock { - pthread_mutex_t lock; -} __attribute__((aligned(CACHE_LINE_SIZE))); /* cache-line aligned */ - -static struct per_thread_lock *per_thread_lock; - -#define OUTER_READ_LOOP 200U -#define INNER_READ_LOOP 100000U -#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP) - -#define OUTER_WRITE_LOOP 10U -#define INNER_WRITE_LOOP 200U -#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP) - -static int num_read; -static int num_write; - -#define NR_READ num_read -#define NR_WRITE num_write - -static cycles_t __attribute__((aligned(CACHE_LINE_SIZE))) *reader_time; -static cycles_t __attribute__((aligned(CACHE_LINE_SIZE))) *writer_time; - -void *thr_reader(void *arg) -{ - int i, j; - cycles_t time1, time2; - long tidx = (long)arg; - - printf("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - sleep(2); - - time1 = get_cycles(); - for (i = 0; i < OUTER_READ_LOOP; i++) { - for (j = 0; j < INNER_READ_LOOP; j++) { - pthread_mutex_lock(&per_thread_lock[tidx].lock); - assert(test_array.a == 8); - pthread_mutex_unlock(&per_thread_lock[tidx].lock); - } - } - time2 = get_cycles(); - - reader_time[tidx] = time2 - time1; - - sleep(2); - printf("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -void *thr_writer(void *arg) -{ - int i, j; - long tidx; - cycles_t time1, time2; - - printf("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - sleep(2); - - for (i = 0; i < OUTER_WRITE_LOOP; i++) { - for (j = 0; j < INNER_WRITE_LOOP; j++) { - time1 = get_cycles(); - for (tidx = 0; tidx < NR_READ; tidx++) { - pthread_mutex_lock(&per_thread_lock[tidx].lock); - } - test_array.a = 8; - for (tidx = NR_READ - 1; tidx >= 0; tidx--) { - pthread_mutex_unlock(&per_thread_lock[tidx].lock); - } - time2 = get_cycles(); - writer_time[(unsigned long)arg] += time2 - time1; - usleep(1); - } - } - - printf("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - return ((void*)2); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - int i; - cycles_t tot_rtime = 0; - cycles_t tot_wtime = 0; - - if (argc < 2) { - printf("Usage : %s nr_readers nr_writers\n", argv[0]); - exit(-1); - } - num_read = atoi(argv[1]); - num_write = atoi(argv[2]); - - reader_time = malloc(sizeof(*reader_time) * num_read); - writer_time = malloc(sizeof(*writer_time) * num_write); - tid_reader = malloc(sizeof(*tid_reader) * num_read); - tid_writer = malloc(sizeof(*tid_writer) * num_write); - - printf("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - per_thread_lock = malloc(sizeof(struct per_thread_lock) * NR_READ); - - for (i = 0; i < NR_READ; i++) { - pthread_mutex_init(&per_thread_lock[i].lock, NULL); - } - for (i = 0; i < NR_READ; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - (void *)(long)i); - if (err != 0) - exit(1); - } - for (i = 0; i < NR_WRITE; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - (void *)(long)i); - if (err != 0) - exit(1); - } - - sleep(10); - - for (i = 0; i < NR_READ; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_rtime += reader_time[i]; - } - for (i = 0; i < NR_WRITE; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_wtime += writer_time[i]; - } - printf("Time per read : %g cycles\n", - (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP)); - printf("Time per write : %g cycles\n", - (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP)); - free(per_thread_lock); - - free(reader_time); - free(writer_time); - free(tid_reader); - free(tid_writer); - - return 0; -} diff --git a/tests/test_qsbr.c b/tests/test_qsbr.c deleted file mode 100644 index 6230510..0000000 --- a/tests/test_qsbr.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * test_urcu.c - * - * Userspace RCU library - test program - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* hardcoded number of CPUs */ -#define NR_CPUS 16384 - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#ifndef DYNAMIC_LINK_TEST -#define _LGPL_SOURCE -#else -#define debug_yield_read() -#endif -#include "urcu-qsbr.h" - -struct test_array { - int a; -}; - -static volatile int test_go, test_stop; - -static unsigned long wdelay; - -static struct test_array *test_rcu_pointer; - -static unsigned long duration; - -/* read-side C.S. duration, in loops */ -static unsigned long rduration; - -static inline void loop_sleep(unsigned long l) -{ - while(l-- != 0) - cpu_relax(); -} - -static int verbose_mode; - -#define printf_verbose(fmt, args...) \ - do { \ - if (verbose_mode) \ - printf(fmt, args); \ - } while (0) - -static unsigned int cpu_affinities[NR_CPUS]; -static unsigned int next_aff = 0; -static int use_affinity = 0; - -pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void set_affinity(void) -{ - cpu_set_t mask; - int cpu; - int ret; - - if (!use_affinity) - return; - - ret = pthread_mutex_lock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } - cpu = cpu_affinities[next_aff++]; - ret = pthread_mutex_unlock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - sched_setaffinity(0, sizeof(mask), &mask); -} - -/* - * returns 0 if test should end. - */ -static int test_duration_write(void) -{ - return !test_stop; -} - -static int test_duration_read(void) -{ - return !test_stop; -} - -static unsigned long long __thread nr_writes; -static unsigned long long __thread nr_reads; - -static unsigned int nr_readers; -static unsigned int nr_writers; - -pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; - -void rcu_copy_mutex_lock(void) -{ - int ret; - ret = pthread_mutex_lock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -} - -void rcu_copy_mutex_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -/* - * malloc/free are reusing memory areas too quickly, which does not let us - * test races appropriately. Use a large circular array for allocations. - * ARRAY_SIZE is larger than nr_writers, which insures we never run over our tail. - */ -#define ARRAY_SIZE (1048576 * nr_writers) -#define ARRAY_POISON 0xDEADBEEF -static int array_index; -static struct test_array *test_array; - -static struct test_array *test_array_alloc(void) -{ - struct test_array *ret; - int index; - - rcu_copy_mutex_lock(); - index = array_index % ARRAY_SIZE; - assert(test_array[index].a == ARRAY_POISON || - test_array[index].a == 0); - ret = &test_array[index]; - array_index++; - if (array_index == ARRAY_SIZE) - array_index = 0; - rcu_copy_mutex_unlock(); - return ret; -} - -static void test_array_free(struct test_array *ptr) -{ - if (!ptr) - return; - rcu_copy_mutex_lock(); - ptr->a = ARRAY_POISON; - rcu_copy_mutex_unlock(); -} - -void *thr_reader(void *_count) -{ - unsigned long long *count = _count; - struct test_array *local_ptr; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - rcu_register_thread(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { - rcu_read_lock(); - local_ptr = rcu_dereference(test_rcu_pointer); - debug_yield_read(); - if (local_ptr) - assert(local_ptr->a == 8); - if (unlikely(rduration)) - loop_sleep(rduration); - rcu_read_unlock(); - nr_reads++; - /* QS each 1024 reads */ - if (unlikely((nr_reads & ((1 << 10) - 1)) == 0)) - rcu_quiescent_state(); - if (unlikely(!test_duration_read())) - break; - } - - rcu_unregister_thread(); - - *count = nr_reads; - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -void *thr_writer(void *_count) -{ - unsigned long long *count = _count; - struct test_array *new, *old; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { - new = test_array_alloc(); - new->a = 8; - old = rcu_publish_content(&test_rcu_pointer, new); - /* can be done after unlock */ - if (old) - old->a = 0; - test_array_free(old); - nr_writes++; - if (unlikely(!test_duration_write())) - break; - if (unlikely(wdelay)) - loop_sleep(wdelay); - } - - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - *count = nr_writes; - return ((void*)2); -} - -void show_usage(int argc, char **argv) -{ - printf("Usage : %s nr_readers nr_writers duration (s)", argv[0]); -#ifdef DEBUG_YIELD - printf(" [-r] [-w] (yield reader and/or writer)"); -#endif - printf(" [-d delay] (writer period (us))"); - printf(" [-c duration] (reader C.S. duration (in loops))"); - printf(" [-v] (verbose output)"); - printf(" [-a cpu#] [-a cpu#]... (affinity)"); - printf("\n"); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - unsigned long long *count_reader, *count_writer; - unsigned long long tot_reads = 0, tot_writes = 0; - int i, a; - - if (argc < 4) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[1], "%u", &nr_readers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[2], "%u", &nr_writers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[3], "%lu", &duration); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - for (i = 4; i < argc; i++) { - if (argv[i][0] != '-') - continue; - switch (argv[i][1]) { -#ifdef DEBUG_YIELD - case 'r': - yield_active |= YIELD_READ; - break; - case 'w': - yield_active |= YIELD_WRITE; - break; -#endif - case 'a': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - a = atoi(argv[++i]); - cpu_affinities[next_aff++] = a; - use_affinity = 1; - printf_verbose("Adding CPU %d affinity\n", a); - break; - case 'c': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - rduration = atol(argv[++i]); - break; - case 'd': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - wdelay = atol(argv[++i]); - break; - case 'v': - verbose_mode = 1; - break; - } - } - - printf_verbose("running test for %lu seconds, %u readers, %u writers.\n", - duration, nr_readers, nr_writers); - printf_verbose("Writer delay : %lu loops.\n", wdelay); - printf_verbose("Reader duration : %lu loops.\n", rduration); - printf_verbose("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - test_array = malloc(sizeof(*test_array) * ARRAY_SIZE); - tid_reader = malloc(sizeof(*tid_reader) * nr_readers); - tid_writer = malloc(sizeof(*tid_writer) * nr_writers); - count_reader = malloc(sizeof(*count_reader) * nr_readers); - count_writer = malloc(sizeof(*count_writer) * nr_writers); - - next_aff = 0; - - for (i = 0; i < nr_readers; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - &count_reader[i]); - if (err != 0) - exit(1); - } - for (i = 0; i < nr_writers; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - &count_writer[i]); - if (err != 0) - exit(1); - } - - smp_mb(); - - test_go = 1; - - sleep(duration); - - test_stop = 1; - - for (i = 0; i < nr_readers; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_reads += count_reader[i]; - } - for (i = 0; i < nr_writers; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_writes += count_writer[i]; - } - - printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads, - tot_writes); - printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu " - "nr_writers %3u " - "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n", - argv[0], duration, nr_readers, rduration, - nr_writers, wdelay, tot_reads, tot_writes, - tot_reads + tot_writes); - test_array_free(test_rcu_pointer); - free(test_array); - free(tid_reader); - free(tid_writer); - free(count_reader); - free(count_writer); - return 0; -} diff --git a/tests/test_qsbr_gc.c b/tests/test_qsbr_gc.c deleted file mode 100644 index 9766067..0000000 --- a/tests/test_qsbr_gc.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * test_urcu_gc.c - * - * Userspace RCU library - test program (with baatch reclamation) - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* hardcoded number of CPUs */ -#define NR_CPUS 16384 - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#define _LGPL_SOURCE -#include - -struct test_array { - int a; -}; - -static volatile int test_go, test_stop; - -static unsigned long wdelay; - -static struct test_array *test_rcu_pointer; - -static unsigned long duration; - -/* read-side C.S. duration, in loops */ -static unsigned long rduration; -static unsigned int reclaim_batch = 1; - -struct reclaim_queue { - void **queue; /* Beginning of queue */ - void **head; /* Insert position */ -}; - -static struct reclaim_queue *pending_reclaims; - - -static inline void loop_sleep(unsigned long l) -{ - while(l-- != 0) - cpu_relax(); -} - -static int verbose_mode; - -#define printf_verbose(fmt, args...) \ - do { \ - if (verbose_mode) \ - printf(fmt, args); \ - } while (0) - -static unsigned int cpu_affinities[NR_CPUS]; -static unsigned int next_aff = 0; -static int use_affinity = 0; - -pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void set_affinity(void) -{ - cpu_set_t mask; - int cpu; - int ret; - - if (!use_affinity) - return; - - ret = pthread_mutex_lock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } - cpu = cpu_affinities[next_aff++]; - ret = pthread_mutex_unlock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - sched_setaffinity(0, sizeof(mask), &mask); -} - -/* - * returns 0 if test should end. - */ -static int test_duration_write(void) -{ - return !test_stop; -} - -static int test_duration_read(void) -{ - return !test_stop; -} - -static unsigned long long __thread nr_writes; -static unsigned long long __thread nr_reads; - -static unsigned int nr_readers; -static unsigned int nr_writers; - -pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; -static -unsigned long long __attribute__((aligned(CACHE_LINE_SIZE))) *tot_nr_writes; - - -void rcu_copy_mutex_lock(void) -{ - int ret; - ret = pthread_mutex_lock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -} - -void rcu_copy_mutex_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -void *thr_reader(void *_count) -{ - unsigned long long *count = _count; - struct test_array *local_ptr; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - rcu_register_thread(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { - _rcu_read_lock(); - local_ptr = _rcu_dereference(test_rcu_pointer); - debug_yield_read(); - if (local_ptr) - assert(local_ptr->a == 8); - if (unlikely(rduration)) - loop_sleep(rduration); - _rcu_read_unlock(); - nr_reads++; - /* QS each 1024 reads */ - if (unlikely((nr_reads & ((1 << 10) - 1)) == 0)) - _rcu_quiescent_state(); - if (unlikely(!test_duration_read())) - break; - } - - rcu_unregister_thread(); - - *count = nr_reads; - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -static void rcu_gc_clear_queue(unsigned long wtidx) -{ - void **p; - - /* Wait for Q.S and empty queue */ - synchronize_rcu(); - - for (p = pending_reclaims[wtidx].queue; - p < pending_reclaims[wtidx].head; p++) { - /* poison */ - if (*p) - ((struct test_array *)*p)->a = 0; - free(*p); - } - pending_reclaims[wtidx].head = pending_reclaims[wtidx].queue; -} - -/* Using per-thread queue */ -static void rcu_gc_reclaim(unsigned long wtidx, void *old) -{ - /* Queue pointer */ - *pending_reclaims[wtidx].head = old; - pending_reclaims[wtidx].head++; - - if (likely(pending_reclaims[wtidx].head - pending_reclaims[wtidx].queue - < reclaim_batch)) - return; - - rcu_gc_clear_queue(wtidx); -} - -void *thr_writer(void *data) -{ - unsigned long wtidx = (unsigned long)data; -#ifdef TEST_LOCAL_GC - struct test_array *old = NULL; -#else - struct test_array *new, *old; -#endif - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { -#ifndef TEST_LOCAL_GC - new = malloc(sizeof(*new)); - new->a = 8; - old = _rcu_xchg_pointer(&test_rcu_pointer, new); -#endif - rcu_gc_reclaim(wtidx, old); - nr_writes++; - if (unlikely(!test_duration_write())) - break; - if (unlikely(wdelay)) - loop_sleep(wdelay); - } - - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - tot_nr_writes[wtidx] = nr_writes; - return ((void*)2); -} - -void show_usage(int argc, char **argv) -{ - printf("Usage : %s nr_readers nr_writers duration (s)", argv[0]); -#ifdef DEBUG_YIELD - printf(" [-r] [-w] (yield reader and/or writer)"); -#endif - printf(" [-d delay] (writer period (us))"); - printf(" [-c duration] (reader C.S. duration (in loops))"); - printf(" [-v] (verbose output)"); - printf(" [-a cpu#] [-a cpu#]... (affinity)"); - printf("\n"); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - unsigned long long *count_reader; - unsigned long long tot_reads = 0, tot_writes = 0; - int i, a; - - if (argc < 4) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[1], "%u", &nr_readers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[2], "%u", &nr_writers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[3], "%lu", &duration); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - for (i = 4; i < argc; i++) { - if (argv[i][0] != '-') - continue; - switch (argv[i][1]) { -#ifdef DEBUG_YIELD - case 'r': - yield_active |= YIELD_READ; - break; - case 'w': - yield_active |= YIELD_WRITE; - break; -#endif - case 'a': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - a = atoi(argv[++i]); - cpu_affinities[next_aff++] = a; - use_affinity = 1; - printf_verbose("Adding CPU %d affinity\n", a); - break; - case 'b': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - reclaim_batch = atol(argv[++i]); - break; - case 'c': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - rduration = atol(argv[++i]); - break; - case 'd': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - wdelay = atol(argv[++i]); - break; - case 'v': - verbose_mode = 1; - break; - } - } - - printf_verbose("running test for %lu seconds, %u readers, %u writers.\n", - duration, nr_readers, nr_writers); - printf_verbose("Writer delay : %lu loops.\n", wdelay); - printf_verbose("Reader duration : %lu loops.\n", rduration); - printf_verbose("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - tid_reader = malloc(sizeof(*tid_reader) * nr_readers); - tid_writer = malloc(sizeof(*tid_writer) * nr_writers); - count_reader = malloc(sizeof(*count_reader) * nr_readers); - tot_nr_writes = malloc(sizeof(*tot_nr_writes) * nr_writers); - pending_reclaims = malloc(sizeof(*pending_reclaims) * nr_writers); - if (reclaim_batch * sizeof(*pending_reclaims[i].queue) - < CACHE_LINE_SIZE) - for (i = 0; i < nr_writers; i++) - pending_reclaims[i].queue = calloc(1, CACHE_LINE_SIZE); - else - for (i = 0; i < nr_writers; i++) - pending_reclaims[i].queue = calloc(reclaim_batch, - sizeof(*pending_reclaims[i].queue)); - for (i = 0; i < nr_writers; i++) - pending_reclaims[i].head = pending_reclaims[i].queue; - - next_aff = 0; - - for (i = 0; i < nr_readers; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - &count_reader[i]); - if (err != 0) - exit(1); - } - for (i = 0; i < nr_writers; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - (void *)(long)i); - if (err != 0) - exit(1); - } - - smp_mb(); - - test_go = 1; - - sleep(duration); - - test_stop = 1; - - for (i = 0; i < nr_readers; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_reads += count_reader[i]; - } - for (i = 0; i < nr_writers; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_writes += tot_nr_writes[i]; - rcu_gc_clear_queue(i); - } - - printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads, - tot_writes); - printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu " - "nr_writers %3u " - "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu " - "batch %u\n", - argv[0], duration, nr_readers, rduration, - nr_writers, wdelay, tot_reads, tot_writes, - tot_reads + tot_writes, reclaim_batch); - free(tid_reader); - free(tid_writer); - free(count_reader); - free(tot_nr_writes); - for (i = 0; i < nr_writers; i++) - free(pending_reclaims[i].queue); - free(pending_reclaims); - - return 0; -} diff --git a/tests/test_qsbr_timing.c b/tests/test_qsbr_timing.c deleted file mode 100644 index bbe983e..0000000 --- a/tests/test_qsbr_timing.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * test_qsbr_timing.c - * - * Userspace QSBR - test program - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#define _LGPL_SOURCE -#include - -pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; - -void rcu_copy_mutex_lock(void) -{ - int ret; - ret = pthread_mutex_lock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -} - -void rcu_copy_mutex_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -struct test_array { - int a; -}; - -static struct test_array *test_rcu_pointer; - -#define OUTER_READ_LOOP 2000U -#define INNER_READ_LOOP 100000U -#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP) - -#define OUTER_WRITE_LOOP 10U -#define INNER_WRITE_LOOP 200U -#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP) - -static int num_read; -static int num_write; - -#define NR_READ num_read -#define NR_WRITE num_write - -static cycles_t __attribute__((aligned(CACHE_LINE_SIZE))) *reader_time; -static cycles_t __attribute__((aligned(CACHE_LINE_SIZE))) *writer_time; - -void *thr_reader(void *arg) -{ - int i, j; - struct test_array *local_ptr; - cycles_t time1, time2; - - printf("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - sleep(2); - - rcu_register_thread(); - - time1 = get_cycles(); - for (i = 0; i < OUTER_READ_LOOP; i++) { - for (j = 0; j < INNER_READ_LOOP; j++) { - _rcu_read_lock(); - local_ptr = _rcu_dereference(test_rcu_pointer); - if (local_ptr) { - assert(local_ptr->a == 8); - } - _rcu_read_unlock(); - } - _rcu_quiescent_state(); - } - time2 = get_cycles(); - - rcu_unregister_thread(); - - reader_time[(unsigned long)arg] = time2 - time1; - - sleep(2); - printf("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -void *thr_writer(void *arg) -{ - int i, j; - struct test_array *new, *old; - cycles_t time1, time2; - - printf("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - sleep(2); - - for (i = 0; i < OUTER_WRITE_LOOP; i++) { - for (j = 0; j < INNER_WRITE_LOOP; j++) { - time1 = get_cycles(); - new = malloc(sizeof(struct test_array)); - rcu_copy_mutex_lock(); - old = test_rcu_pointer; - if (old) { - assert(old->a == 8); - } - new->a = 8; - old = _rcu_publish_content(&test_rcu_pointer, new); - rcu_copy_mutex_unlock(); - /* can be done after unlock */ - if (old) { - old->a = 0; - } - free(old); - time2 = get_cycles(); - writer_time[(unsigned long)arg] += time2 - time1; - usleep(1); - } - } - - printf("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - return ((void*)2); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - int i; - cycles_t tot_rtime = 0; - cycles_t tot_wtime = 0; - - if (argc < 2) { - printf("Usage : %s nr_readers nr_writers\n", argv[0]); - exit(-1); - } - num_read = atoi(argv[1]); - num_write = atoi(argv[2]); - - reader_time = malloc(sizeof(*reader_time) * num_read); - writer_time = malloc(sizeof(*writer_time) * num_write); - tid_reader = malloc(sizeof(*tid_reader) * num_read); - tid_writer = malloc(sizeof(*tid_writer) * num_write); - - printf("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - for (i = 0; i < NR_READ; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - (void *)(long)i); - if (err != 0) - exit(1); - } - for (i = 0; i < NR_WRITE; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - (void *)(long)i); - if (err != 0) - exit(1); - } - - sleep(10); - - for (i = 0; i < NR_READ; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_rtime += reader_time[i]; - } - for (i = 0; i < NR_WRITE; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_wtime += writer_time[i]; - } - free(test_rcu_pointer); - printf("Time per read : %g cycles\n", - (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP)); - printf("Time per write : %g cycles\n", - (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP)); - - free(reader_time); - free(writer_time); - free(tid_reader); - free(tid_writer); - - return 0; -} diff --git a/tests/test_rwlock.c b/tests/test_rwlock.c deleted file mode 100644 index 923ecad..0000000 --- a/tests/test_rwlock.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * test_urcu.c - * - * Userspace RCU library - test program - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* hardcoded number of CPUs */ -#define NR_CPUS 16384 - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#ifndef DYNAMIC_LINK_TEST -#define _LGPL_SOURCE -#else -#define debug_yield_read() -#endif -#include - -struct test_array { - int a; -}; - -pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER; - -static volatile int test_go, test_stop; - -static unsigned long wdelay; - -static volatile struct test_array test_array = { 8 }; - -static unsigned long duration; - -/* read-side C.S. duration, in loops */ -static unsigned long rduration; - -static inline void loop_sleep(unsigned long l) -{ - while(l-- != 0) - cpu_relax(); -} - -static int verbose_mode; - -#define printf_verbose(fmt, args...) \ - do { \ - if (verbose_mode) \ - printf(fmt, args); \ - } while (0) - -static unsigned int cpu_affinities[NR_CPUS]; -static unsigned int next_aff = 0; -static int use_affinity = 0; - -pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void set_affinity(void) -{ - cpu_set_t mask; - int cpu; - int ret; - - if (!use_affinity) - return; - - ret = pthread_mutex_lock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } - cpu = cpu_affinities[next_aff++]; - ret = pthread_mutex_unlock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - sched_setaffinity(0, sizeof(mask), &mask); -} - -/* - * returns 0 if test should end. - */ -static int test_duration_write(void) -{ - return !test_stop; -} - -static int test_duration_read(void) -{ - return !test_stop; -} - -static unsigned long long __thread nr_writes; -static unsigned long long __thread nr_reads; - -static unsigned int nr_readers; -static unsigned int nr_writers; - -pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; - -void rcu_copy_mutex_lock(void) -{ - int ret; - ret = pthread_mutex_lock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -} - -void rcu_copy_mutex_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -void *thr_reader(void *_count) -{ - unsigned long long *count = _count; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - while (!test_go) - { - } - - for (;;) { - pthread_rwlock_rdlock(&lock); - assert(test_array.a == 8); - if (unlikely(rduration)) - loop_sleep(rduration); - pthread_rwlock_unlock(&lock); - nr_reads++; - if (unlikely(!test_duration_read())) - break; - } - - *count = nr_reads; - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -void *thr_writer(void *_count) -{ - unsigned long long *count = _count; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { - pthread_rwlock_wrlock(&lock); - test_array.a = 0; - test_array.a = 8; - pthread_rwlock_unlock(&lock); - nr_writes++; - if (unlikely(!test_duration_write())) - break; - if (unlikely(wdelay)) - loop_sleep(wdelay); - } - - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - *count = nr_writes; - return ((void*)2); -} - -void show_usage(int argc, char **argv) -{ - printf("Usage : %s nr_readers nr_writers duration (s)", argv[0]); -#ifdef DEBUG_YIELD - printf(" [-r] [-w] (yield reader and/or writer)"); -#endif - printf(" [-d delay] (writer period (us))"); - printf(" [-c duration] (reader C.S. duration (in loops))"); - printf(" [-v] (verbose output)"); - printf(" [-a cpu#] [-a cpu#]... (affinity)"); - printf("\n"); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - unsigned long long *count_reader, *count_writer; - unsigned long long tot_reads = 0, tot_writes = 0; - int i, a; - - if (argc < 4) { - show_usage(argc, argv); - return -1; - } - smp_mb(); - - err = sscanf(argv[1], "%u", &nr_readers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[2], "%u", &nr_writers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[3], "%lu", &duration); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - for (i = 4; i < argc; i++) { - if (argv[i][0] != '-') - continue; - switch (argv[i][1]) { -#ifdef DEBUG_YIELD - case 'r': - yield_active |= YIELD_READ; - break; - case 'w': - yield_active |= YIELD_WRITE; - break; -#endif - case 'a': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - a = atoi(argv[++i]); - cpu_affinities[next_aff++] = a; - use_affinity = 1; - printf_verbose("Adding CPU %d affinity\n", a); - break; - case 'c': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - rduration = atol(argv[++i]); - break; - case 'd': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - wdelay = atol(argv[++i]); - break; - case 'v': - verbose_mode = 1; - break; - } - } - - printf_verbose("running test for %lu seconds, %u readers, %u writers.\n", - duration, nr_readers, nr_writers); - printf_verbose("Writer delay : %lu loops.\n", wdelay); - printf_verbose("Reader duration : %lu loops.\n", rduration); - printf_verbose("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - tid_reader = malloc(sizeof(*tid_reader) * nr_readers); - tid_writer = malloc(sizeof(*tid_writer) * nr_writers); - count_reader = malloc(sizeof(*count_reader) * nr_readers); - count_writer = malloc(sizeof(*count_writer) * nr_writers); - - next_aff = 0; - - for (i = 0; i < nr_readers; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - &count_reader[i]); - if (err != 0) - exit(1); - } - for (i = 0; i < nr_writers; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - &count_writer[i]); - if (err != 0) - exit(1); - } - - smp_mb(); - - test_go = 1; - - sleep(duration); - - test_stop = 1; - - for (i = 0; i < nr_readers; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_reads += count_reader[i]; - } - for (i = 0; i < nr_writers; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_writes += count_writer[i]; - } - - printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads, - tot_writes); - printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu " - "nr_writers %3u " - "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n", - argv[0], duration, nr_readers, rduration, - nr_writers, wdelay, tot_reads, tot_writes, - tot_reads + tot_writes); - - free(tid_reader); - free(tid_writer); - free(count_reader); - free(count_writer); - return 0; -} diff --git a/tests/test_rwlock_timing.c b/tests/test_rwlock_timing.c deleted file mode 100644 index c5c9478..0000000 --- a/tests/test_rwlock_timing.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * test_urcu.c - * - * Userspace RCU library - test program - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#include - -struct test_array { - int a; -}; - -pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER; - -static struct test_array test_array = { 8 }; - -#define OUTER_READ_LOOP 200U -#define INNER_READ_LOOP 100000U -#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP) - -#define OUTER_WRITE_LOOP 10U -#define INNER_WRITE_LOOP 200U -#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP) - -static int num_read; -static int num_write; - -#define NR_READ num_read -#define NR_WRITE num_write - -static cycles_t __attribute__((aligned(CACHE_LINE_SIZE))) *reader_time; -static cycles_t __attribute__((aligned(CACHE_LINE_SIZE))) *writer_time; - -void *thr_reader(void *arg) -{ - int i, j; - cycles_t time1, time2; - - printf("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - sleep(2); - - time1 = get_cycles(); - for (i = 0; i < OUTER_READ_LOOP; i++) { - for (j = 0; j < INNER_READ_LOOP; j++) { - pthread_rwlock_rdlock(&lock); - assert(test_array.a == 8); - pthread_rwlock_unlock(&lock); - } - } - time2 = get_cycles(); - - reader_time[(unsigned long)arg] = time2 - time1; - - sleep(2); - printf("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -void *thr_writer(void *arg) -{ - int i, j; - cycles_t time1, time2; - - printf("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - sleep(2); - - for (i = 0; i < OUTER_WRITE_LOOP; i++) { - for (j = 0; j < INNER_WRITE_LOOP; j++) { - time1 = get_cycles(); - pthread_rwlock_wrlock(&lock); - test_array.a = 8; - pthread_rwlock_unlock(&lock); - time2 = get_cycles(); - writer_time[(unsigned long)arg] += time2 - time1; - usleep(1); - } - } - - printf("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - return ((void*)2); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - int i; - cycles_t tot_rtime = 0; - cycles_t tot_wtime = 0; - - if (argc < 2) { - printf("Usage : %s nr_readers nr_writers\n", argv[0]); - exit(-1); - } - num_read = atoi(argv[1]); - num_write = atoi(argv[2]); - - reader_time = malloc(sizeof(*reader_time) * num_read); - writer_time = malloc(sizeof(*writer_time) * num_write); - tid_reader = malloc(sizeof(*tid_reader) * num_read); - tid_writer = malloc(sizeof(*tid_writer) * num_write); - - printf("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - for (i = 0; i < NR_READ; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - (void *)(long)i); - if (err != 0) - exit(1); - } - for (i = 0; i < NR_WRITE; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - (void *)(long)i); - if (err != 0) - exit(1); - } - - sleep(10); - - for (i = 0; i < NR_READ; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_rtime += reader_time[i]; - } - for (i = 0; i < NR_WRITE; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_wtime += writer_time[i]; - } - printf("Time per read : %g cycles\n", - (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP)); - printf("Time per write : %g cycles\n", - (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP)); - - free(reader_time); - free(writer_time); - free(tid_reader); - free(tid_writer); - - return 0; -} diff --git a/tests/test_uatomic.c b/tests/test_uatomic.c deleted file mode 100644 index 6c11a2d..0000000 --- a/tests/test_uatomic.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include - -#if (defined(__i386__) || defined(__x86_64__)) -#define HAS_ATOMIC_BYTE -#define HAS_ATOMIC_SHORT -#endif - -struct testvals { -#ifdef HAS_ATOMIC_BYTE - unsigned char c; -#endif -#ifdef HAS_ATOMIC_SHORT - unsigned short s; -#endif - unsigned int i; - unsigned long l; -}; - -static struct testvals vals; - -#define do_test(ptr) \ -do { \ - __typeof__(*(ptr)) v; \ - \ - uatomic_add(ptr, 10); \ - assert(uatomic_read(ptr) == 10); \ - uatomic_add(ptr, -11UL); \ - assert(uatomic_read(ptr) == (__typeof__(*(ptr)))-1UL); \ - v = uatomic_cmpxchg(ptr, -1UL, 22); \ - assert(uatomic_read(ptr) == 22); \ - assert(v == (__typeof__(*(ptr)))-1UL); \ - v = uatomic_cmpxchg(ptr, 33, 44); \ - assert(uatomic_read(ptr) == 22); \ - assert(v == 22); \ - v = uatomic_xchg(ptr, 55); \ - assert(uatomic_read(ptr) == 55); \ - assert(v == 22); \ - uatomic_set(ptr, 22); \ - uatomic_inc(ptr); \ - assert(uatomic_read(ptr) == 23); \ - uatomic_dec(ptr); \ - assert(uatomic_read(ptr) == 22); \ - v = uatomic_add_return(ptr, 100); \ - assert(v == 122); \ - assert(uatomic_read(ptr) == 122); \ - v = uatomic_sub_return(ptr, 1); \ - assert(v == 121); \ - assert(uatomic_read(ptr) == 121); \ -} while (0) - -int main(int argc, char **argv) -{ -#ifdef HAS_ATOMIC_BYTE - do_test(&vals.c); -#endif -#ifdef HAS_ATOMIC_SHORT - do_test(&vals.s); -#endif - do_test(&vals.i); - do_test(&vals.l); - printf("Atomic ops test OK\n"); - - return 0; -} diff --git a/tests/test_urcu.c b/tests/test_urcu.c deleted file mode 100644 index 3b838c1..0000000 --- a/tests/test_urcu.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * test_urcu.c - * - * Userspace RCU library - test program - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* hardcoded number of CPUs */ -#define NR_CPUS 16384 - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#ifndef DYNAMIC_LINK_TEST -#define _LGPL_SOURCE -#else -#define debug_yield_read() -#endif -#include - -struct test_array { - int a; -}; - -static volatile int test_go, test_stop; - -static unsigned long wdelay; - -static struct test_array *test_rcu_pointer; - -static unsigned long duration; - -/* read-side C.S. duration, in loops */ -static unsigned long rduration; - -static inline void loop_sleep(unsigned long l) -{ - while(l-- != 0) - cpu_relax(); -} - -static int verbose_mode; - -#define printf_verbose(fmt, args...) \ - do { \ - if (verbose_mode) \ - printf(fmt, args); \ - } while (0) - -static unsigned int cpu_affinities[NR_CPUS]; -static unsigned int next_aff = 0; -static int use_affinity = 0; - -pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void set_affinity(void) -{ - cpu_set_t mask; - int cpu; - int ret; - - if (!use_affinity) - return; - - ret = pthread_mutex_lock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } - cpu = cpu_affinities[next_aff++]; - ret = pthread_mutex_unlock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - sched_setaffinity(0, sizeof(mask), &mask); -} - -/* - * returns 0 if test should end. - */ -static int test_duration_write(void) -{ - return !test_stop; -} - -static int test_duration_read(void) -{ - return !test_stop; -} - -static unsigned long long __thread nr_writes; -static unsigned long long __thread nr_reads; - -static unsigned int nr_readers; -static unsigned int nr_writers; - -pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; - -void rcu_copy_mutex_lock(void) -{ - int ret; - ret = pthread_mutex_lock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -} - -void rcu_copy_mutex_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -/* - * malloc/free are reusing memory areas too quickly, which does not let us - * test races appropriately. Use a large circular array for allocations. - * ARRAY_SIZE is larger than nr_writers, which insures we never run over our tail. - */ -#define ARRAY_SIZE (1048576 * nr_writers) -#define ARRAY_POISON 0xDEADBEEF -static int array_index; -static struct test_array *test_array; - -static struct test_array *test_array_alloc(void) -{ - struct test_array *ret; - int index; - - rcu_copy_mutex_lock(); - index = array_index % ARRAY_SIZE; - assert(test_array[index].a == ARRAY_POISON || - test_array[index].a == 0); - ret = &test_array[index]; - array_index++; - if (array_index == ARRAY_SIZE) - array_index = 0; - rcu_copy_mutex_unlock(); - return ret; -} - -static void test_array_free(struct test_array *ptr) -{ - if (!ptr) - return; - rcu_copy_mutex_lock(); - ptr->a = ARRAY_POISON; - rcu_copy_mutex_unlock(); -} - -void *thr_reader(void *_count) -{ - unsigned long long *count = _count; - struct test_array *local_ptr; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - rcu_register_thread(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { - rcu_read_lock(); - local_ptr = rcu_dereference(test_rcu_pointer); - debug_yield_read(); - if (local_ptr) - assert(local_ptr->a == 8); - if (unlikely(rduration)) - loop_sleep(rduration); - rcu_read_unlock(); - nr_reads++; - if (unlikely(!test_duration_read())) - break; - } - - rcu_unregister_thread(); - - *count = nr_reads; - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -void *thr_writer(void *_count) -{ - unsigned long long *count = _count; - struct test_array *new, *old; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { - new = test_array_alloc(); - new->a = 8; - old = rcu_publish_content(&test_rcu_pointer, new); - if (old) - old->a = 0; - test_array_free(old); - nr_writes++; - if (unlikely(!test_duration_write())) - break; - if (unlikely(wdelay)) - loop_sleep(wdelay); - } - - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - *count = nr_writes; - return ((void*)2); -} - -void show_usage(int argc, char **argv) -{ - printf("Usage : %s nr_readers nr_writers duration (s)", argv[0]); -#ifdef DEBUG_YIELD - printf(" [-r] [-w] (yield reader and/or writer)"); -#endif - printf(" [-d delay] (writer period (us))"); - printf(" [-c duration] (reader C.S. duration (in loops))"); - printf(" [-v] (verbose output)"); - printf(" [-a cpu#] [-a cpu#]... (affinity)"); - printf("\n"); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - unsigned long long *count_reader, *count_writer; - unsigned long long tot_reads = 0, tot_writes = 0; - int i, a; - - if (argc < 4) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[1], "%u", &nr_readers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[2], "%u", &nr_writers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[3], "%lu", &duration); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - for (i = 4; i < argc; i++) { - if (argv[i][0] != '-') - continue; - switch (argv[i][1]) { -#ifdef DEBUG_YIELD - case 'r': - yield_active |= YIELD_READ; - break; - case 'w': - yield_active |= YIELD_WRITE; - break; -#endif - case 'a': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - a = atoi(argv[++i]); - cpu_affinities[next_aff++] = a; - use_affinity = 1; - printf_verbose("Adding CPU %d affinity\n", a); - break; - case 'c': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - rduration = atol(argv[++i]); - break; - case 'd': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - wdelay = atol(argv[++i]); - break; - case 'v': - verbose_mode = 1; - break; - } - } - - printf_verbose("running test for %lu seconds, %u readers, %u writers.\n", - duration, nr_readers, nr_writers); - printf_verbose("Writer delay : %lu loops.\n", wdelay); - printf_verbose("Reader duration : %lu loops.\n", rduration); - printf_verbose("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - test_array = malloc(sizeof(*test_array) * ARRAY_SIZE); - tid_reader = malloc(sizeof(*tid_reader) * nr_readers); - tid_writer = malloc(sizeof(*tid_writer) * nr_writers); - count_reader = malloc(sizeof(*count_reader) * nr_readers); - count_writer = malloc(sizeof(*count_writer) * nr_writers); - - next_aff = 0; - - for (i = 0; i < nr_readers; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - &count_reader[i]); - if (err != 0) - exit(1); - } - for (i = 0; i < nr_writers; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - &count_writer[i]); - if (err != 0) - exit(1); - } - - smp_mb(); - - test_go = 1; - - sleep(duration); - - test_stop = 1; - - for (i = 0; i < nr_readers; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_reads += count_reader[i]; - } - for (i = 0; i < nr_writers; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_writes += count_writer[i]; - } - - printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads, - tot_writes); - printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu " - "nr_writers %3u " - "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n", - argv[0], duration, nr_readers, rduration, - nr_writers, wdelay, tot_reads, tot_writes, - tot_reads + tot_writes); - test_array_free(test_rcu_pointer); - free(test_array); - free(tid_reader); - free(tid_writer); - free(count_reader); - free(count_writer); - return 0; -} diff --git a/tests/test_urcu_defer.c b/tests/test_urcu_defer.c deleted file mode 100644 index 08e3e60..0000000 --- a/tests/test_urcu_defer.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * test_urcu_defer.c - * - * Userspace RCU library - test program (with automatic reclamation) - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* hardcoded number of CPUs */ -#define NR_CPUS 16384 - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#ifndef DYNAMIC_LINK_TEST -#define _LGPL_SOURCE -#else -#define debug_yield_read() -#endif -#include -#include - -struct test_array { - int a; -}; - -static volatile int test_go, test_stop; - -static unsigned long wdelay; - -static struct test_array *test_rcu_pointer; - -static unsigned long duration; - -/* read-side C.S. duration, in loops */ -static unsigned long rduration; - -static inline void loop_sleep(unsigned long l) -{ - while(l-- != 0) - cpu_relax(); -} - -static int verbose_mode; - -#define printf_verbose(fmt, args...) \ - do { \ - if (verbose_mode) \ - printf(fmt, args); \ - } while (0) - -static unsigned int cpu_affinities[NR_CPUS]; -static unsigned int next_aff = 0; -static int use_affinity = 0; - -pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void set_affinity(void) -{ - cpu_set_t mask; - int cpu; - int ret; - - if (!use_affinity) - return; - - ret = pthread_mutex_lock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } - cpu = cpu_affinities[next_aff++]; - ret = pthread_mutex_unlock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - sched_setaffinity(0, sizeof(mask), &mask); -} - -/* - * returns 0 if test should end. - */ -static int test_duration_write(void) -{ - return !test_stop; -} - -static int test_duration_read(void) -{ - return !test_stop; -} - -static unsigned long long __thread nr_writes; -static unsigned long long __thread nr_reads; - -static -unsigned long long __attribute__((aligned(CACHE_LINE_SIZE))) *tot_nr_writes; - -static unsigned int nr_readers; -static unsigned int nr_writers; - -pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; - -void rcu_copy_mutex_lock(void) -{ - int ret; - ret = pthread_mutex_lock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -} - -void rcu_copy_mutex_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -void *thr_reader(void *_count) -{ - unsigned long long *count = _count; - struct test_array *local_ptr; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - rcu_register_thread(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { - rcu_read_lock(); - local_ptr = rcu_dereference(test_rcu_pointer); - debug_yield_read(); - if (local_ptr) - assert(local_ptr->a == 8); - if (unlikely(rduration)) - loop_sleep(rduration); - rcu_read_unlock(); - nr_reads++; - if (unlikely(!test_duration_read())) - break; - } - - rcu_unregister_thread(); - - *count = nr_reads; - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -static void test_cb2(void *data) -{ -} - -static void test_cb1(void *data) -{ -} - -void *thr_writer(void *data) -{ - unsigned long wtidx = (unsigned long)data; - struct test_array *new, *old = NULL; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - rcu_defer_register_thread(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { - new = malloc(sizeof(*new)); - new->a = 8; - old = rcu_xchg_pointer(&test_rcu_pointer, new); - call_rcu(free, old); - call_rcu(test_cb1, old); - call_rcu(test_cb1, (void *)-2L); - call_rcu(test_cb1, (void *)-2L); - call_rcu(test_cb1, old); - call_rcu(test_cb2, (void *)-2L); - call_rcu(test_cb2, (void *)-4L); - call_rcu(test_cb2, (void *)-2L); - nr_writes++; - if (unlikely(!test_duration_write())) - break; - if (unlikely(wdelay)) - loop_sleep(wdelay); - } - - rcu_defer_unregister_thread(); - - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - tot_nr_writes[wtidx] = nr_writes; - return ((void*)2); -} - -void show_usage(int argc, char **argv) -{ - printf("Usage : %s nr_readers nr_writers duration (s)", argv[0]); -#ifdef DEBUG_YIELD - printf(" [-r] [-w] (yield reader and/or writer)"); -#endif - printf(" [-d delay] (writer period (us))"); - printf(" [-c duration] (reader C.S. duration (in loops))"); - printf(" [-v] (verbose output)"); - printf(" [-a cpu#] [-a cpu#]... (affinity)"); - printf("\n"); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - unsigned long long *count_reader; - unsigned long long tot_reads = 0, tot_writes = 0; - int i, a; - - if (argc < 4) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[1], "%u", &nr_readers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[2], "%u", &nr_writers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[3], "%lu", &duration); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - for (i = 4; i < argc; i++) { - if (argv[i][0] != '-') - continue; - switch (argv[i][1]) { -#ifdef DEBUG_YIELD - case 'r': - yield_active |= YIELD_READ; - break; - case 'w': - yield_active |= YIELD_WRITE; - break; -#endif - case 'a': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - a = atoi(argv[++i]); - cpu_affinities[next_aff++] = a; - use_affinity = 1; - printf_verbose("Adding CPU %d affinity\n", a); - break; - case 'c': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - rduration = atol(argv[++i]); - break; - case 'd': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - wdelay = atol(argv[++i]); - break; - case 'v': - verbose_mode = 1; - break; - } - } - - printf_verbose("running test for %lu seconds, %u readers, %u writers.\n", - duration, nr_readers, nr_writers); - printf_verbose("Writer delay : %lu loops.\n", wdelay); - printf_verbose("Reader duration : %lu loops.\n", rduration); - printf_verbose("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - tid_reader = malloc(sizeof(*tid_reader) * nr_readers); - tid_writer = malloc(sizeof(*tid_writer) * nr_writers); - count_reader = malloc(sizeof(*count_reader) * nr_readers); - tot_nr_writes = malloc(sizeof(*tot_nr_writes) * nr_writers); - - next_aff = 0; - - for (i = 0; i < nr_readers; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - &count_reader[i]); - if (err != 0) - exit(1); - } - for (i = 0; i < nr_writers; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - (void *)(long)i); - if (err != 0) - exit(1); - } - - smp_mb(); - - test_go = 1; - - sleep(duration); - - test_stop = 1; - - for (i = 0; i < nr_readers; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_reads += count_reader[i]; - } - for (i = 0; i < nr_writers; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_writes += tot_nr_writes[i]; - } - - printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads, - tot_writes); - printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu " - "nr_writers %3u " - "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n", - argv[0], duration, nr_readers, rduration, - nr_writers, wdelay, tot_reads, tot_writes, - tot_reads + tot_writes); - free(tid_reader); - free(tid_writer); - free(count_reader); - free(tot_nr_writes); - - return 0; -} diff --git a/tests/test_urcu_gc.c b/tests/test_urcu_gc.c deleted file mode 100644 index 162fae0..0000000 --- a/tests/test_urcu_gc.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * test_urcu_gc.c - * - * Userspace RCU library - test program (with baatch reclamation) - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* hardcoded number of CPUs */ -#define NR_CPUS 16384 - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#ifndef DYNAMIC_LINK_TEST -#define _LGPL_SOURCE -#else -#define debug_yield_read() -#endif -#include - -struct test_array { - int a; -}; - -static volatile int test_go, test_stop; - -static unsigned long wdelay; - -static struct test_array *test_rcu_pointer; - -static unsigned int reclaim_batch = 1; - -struct reclaim_queue { - void **queue; /* Beginning of queue */ - void **head; /* Insert position */ -}; - -static struct reclaim_queue *pending_reclaims; - -static unsigned long duration; - -/* read-side C.S. duration, in loops */ -static unsigned long rduration; - -static inline void loop_sleep(unsigned long l) -{ - while(l-- != 0) - cpu_relax(); -} - -static int verbose_mode; - -#define printf_verbose(fmt, args...) \ - do { \ - if (verbose_mode) \ - printf(fmt, args); \ - } while (0) - -static unsigned int cpu_affinities[NR_CPUS]; -static unsigned int next_aff = 0; -static int use_affinity = 0; - -pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void set_affinity(void) -{ - cpu_set_t mask; - int cpu; - int ret; - - if (!use_affinity) - return; - - ret = pthread_mutex_lock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } - cpu = cpu_affinities[next_aff++]; - ret = pthread_mutex_unlock(&affinity_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - sched_setaffinity(0, sizeof(mask), &mask); -} - -/* - * returns 0 if test should end. - */ -static int test_duration_write(void) -{ - return !test_stop; -} - -static int test_duration_read(void) -{ - return !test_stop; -} - -static unsigned long long __thread nr_writes; -static unsigned long long __thread nr_reads; - -static -unsigned long long __attribute__((aligned(CACHE_LINE_SIZE))) *tot_nr_writes; - -static unsigned int nr_readers; -static unsigned int nr_writers; - -pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; - -void rcu_copy_mutex_lock(void) -{ - int ret; - ret = pthread_mutex_lock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -} - -void rcu_copy_mutex_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -void *thr_reader(void *_count) -{ - unsigned long long *count = _count; - struct test_array *local_ptr; - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - rcu_register_thread(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { - rcu_read_lock(); - local_ptr = rcu_dereference(test_rcu_pointer); - debug_yield_read(); - if (local_ptr) - assert(local_ptr->a == 8); - if (unlikely(rduration)) - loop_sleep(rduration); - rcu_read_unlock(); - nr_reads++; - if (unlikely(!test_duration_read())) - break; - } - - rcu_unregister_thread(); - - *count = nr_reads; - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -static void rcu_gc_clear_queue(unsigned long wtidx) -{ - void **p; - - /* Wait for Q.S and empty queue */ - synchronize_rcu(); - - for (p = pending_reclaims[wtidx].queue; - p < pending_reclaims[wtidx].head; p++) { - /* poison */ - if (*p) - ((struct test_array *)*p)->a = 0; - free(*p); - } - pending_reclaims[wtidx].head = pending_reclaims[wtidx].queue; -} - -/* Using per-thread queue */ -static void rcu_gc_reclaim(unsigned long wtidx, void *old) -{ - /* Queue pointer */ - *pending_reclaims[wtidx].head = old; - pending_reclaims[wtidx].head++; - - if (likely(pending_reclaims[wtidx].head - pending_reclaims[wtidx].queue - < reclaim_batch)) - return; - - rcu_gc_clear_queue(wtidx); -} - -void *thr_writer(void *data) -{ - unsigned long wtidx = (unsigned long)data; -#ifdef TEST_LOCAL_GC - struct test_array *old = NULL; -#else - struct test_array *new, *old; -#endif - - printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - - set_affinity(); - - while (!test_go) - { - } - smp_mb(); - - for (;;) { -#ifndef TEST_LOCAL_GC - new = malloc(sizeof(*new)); - new->a = 8; - old = rcu_xchg_pointer(&test_rcu_pointer, new); -#endif - rcu_gc_reclaim(wtidx, old); - nr_writes++; - if (unlikely(!test_duration_write())) - break; - if (unlikely(wdelay)) - loop_sleep(wdelay); - } - - printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - tot_nr_writes[wtidx] = nr_writes; - return ((void*)2); -} - -void show_usage(int argc, char **argv) -{ - printf("Usage : %s nr_readers nr_writers duration (s)", argv[0]); -#ifdef DEBUG_YIELD - printf(" [-r] [-w] (yield reader and/or writer)"); -#endif - printf(" [-d delay] (writer period (us))"); - printf(" [-c duration] (reader C.S. duration (in loops))"); - printf(" [-v] (verbose output)"); - printf(" [-a cpu#] [-a cpu#]... (affinity)"); - printf("\n"); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - unsigned long long *count_reader; - unsigned long long tot_reads = 0, tot_writes = 0; - int i, a; - - if (argc < 4) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[1], "%u", &nr_readers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[2], "%u", &nr_writers); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - err = sscanf(argv[3], "%lu", &duration); - if (err != 1) { - show_usage(argc, argv); - return -1; - } - - for (i = 4; i < argc; i++) { - if (argv[i][0] != '-') - continue; - switch (argv[i][1]) { -#ifdef DEBUG_YIELD - case 'r': - yield_active |= YIELD_READ; - break; - case 'w': - yield_active |= YIELD_WRITE; - break; -#endif - case 'a': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - a = atoi(argv[++i]); - cpu_affinities[next_aff++] = a; - use_affinity = 1; - printf_verbose("Adding CPU %d affinity\n", a); - break; - case 'b': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - reclaim_batch = atol(argv[++i]); - break; - case 'c': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - rduration = atol(argv[++i]); - break; - case 'd': - if (argc < i + 2) { - show_usage(argc, argv); - return -1; - } - wdelay = atol(argv[++i]); - break; - case 'v': - verbose_mode = 1; - break; - } - } - - printf_verbose("running test for %lu seconds, %u readers, %u writers.\n", - duration, nr_readers, nr_writers); - printf_verbose("Writer delay : %lu loops.\n", wdelay); - printf_verbose("Reader duration : %lu loops.\n", rduration); - printf_verbose("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - tid_reader = malloc(sizeof(*tid_reader) * nr_readers); - tid_writer = malloc(sizeof(*tid_writer) * nr_writers); - count_reader = malloc(sizeof(*count_reader) * nr_readers); - tot_nr_writes = malloc(sizeof(*tot_nr_writes) * nr_writers); - pending_reclaims = malloc(sizeof(*pending_reclaims) * nr_writers); - if (reclaim_batch * sizeof(*pending_reclaims[i].queue) - < CACHE_LINE_SIZE) - for (i = 0; i < nr_writers; i++) - pending_reclaims[i].queue = calloc(1, CACHE_LINE_SIZE); - else - for (i = 0; i < nr_writers; i++) - pending_reclaims[i].queue = calloc(reclaim_batch, - sizeof(*pending_reclaims[i].queue)); - for (i = 0; i < nr_writers; i++) - pending_reclaims[i].head = pending_reclaims[i].queue; - - next_aff = 0; - - for (i = 0; i < nr_readers; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - &count_reader[i]); - if (err != 0) - exit(1); - } - for (i = 0; i < nr_writers; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - (void *)(long)i); - if (err != 0) - exit(1); - } - - smp_mb(); - - test_go = 1; - - sleep(duration); - - test_stop = 1; - - for (i = 0; i < nr_readers; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_reads += count_reader[i]; - } - for (i = 0; i < nr_writers; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_writes += tot_nr_writes[i]; - rcu_gc_clear_queue(i); - } - - printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads, - tot_writes); - printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu " - "nr_writers %3u " - "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu " - "batch %u\n", - argv[0], duration, nr_readers, rduration, - nr_writers, wdelay, tot_reads, tot_writes, - tot_reads + tot_writes, reclaim_batch); - free(tid_reader); - free(tid_writer); - free(count_reader); - free(tot_nr_writes); - for (i = 0; i < nr_writers; i++) - free(pending_reclaims[i].queue); - free(pending_reclaims); - - return 0; -} diff --git a/tests/test_urcu_timing.c b/tests/test_urcu_timing.c deleted file mode 100644 index 13c0993..0000000 --- a/tests/test_urcu_timing.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * test_urcu.c - * - * Userspace RCU library - test program - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -#define _LGPL_SOURCE -#include - -pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; - -void rcu_copy_mutex_lock(void) -{ - int ret; - ret = pthread_mutex_lock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -} - -void rcu_copy_mutex_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&rcu_copy_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -struct test_array { - int a; -}; - -static struct test_array *test_rcu_pointer; - -#define OUTER_READ_LOOP 2000U -#define INNER_READ_LOOP 100000U -#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP) - -#define OUTER_WRITE_LOOP 10U -#define INNER_WRITE_LOOP 200U -#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP) - -static int num_read; -static int num_write; - -#define NR_READ num_read -#define NR_WRITE num_write - -static cycles_t __attribute__((aligned(CACHE_LINE_SIZE))) *reader_time; -static cycles_t __attribute__((aligned(CACHE_LINE_SIZE))) *writer_time; - -void *thr_reader(void *arg) -{ - int i, j; - struct test_array *local_ptr; - cycles_t time1, time2; - - printf("thread_begin %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - sleep(2); - - rcu_register_thread(); - - time1 = get_cycles(); - for (i = 0; i < OUTER_READ_LOOP; i++) { - for (j = 0; j < INNER_READ_LOOP; j++) { - rcu_read_lock(); - local_ptr = rcu_dereference(test_rcu_pointer); - if (local_ptr) { - assert(local_ptr->a == 8); - } - rcu_read_unlock(); - } - } - time2 = get_cycles(); - - rcu_unregister_thread(); - - reader_time[(unsigned long)arg] = time2 - time1; - - sleep(2); - printf("thread_end %s, thread id : %lx, tid %lu\n", - "reader", pthread_self(), (unsigned long)gettid()); - return ((void*)1); - -} - -void *thr_writer(void *arg) -{ - int i, j; - struct test_array *new, *old; - cycles_t time1, time2; - - printf("thread_begin %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - sleep(2); - - for (i = 0; i < OUTER_WRITE_LOOP; i++) { - for (j = 0; j < INNER_WRITE_LOOP; j++) { - time1 = get_cycles(); - new = malloc(sizeof(struct test_array)); - rcu_copy_mutex_lock(); - old = test_rcu_pointer; - if (old) { - assert(old->a == 8); - } - new->a = 8; - old = rcu_publish_content(&test_rcu_pointer, new); - rcu_copy_mutex_unlock(); - /* can be done after unlock */ - if (old) { - old->a = 0; - } - free(old); - time2 = get_cycles(); - writer_time[(unsigned long)arg] += time2 - time1; - usleep(1); - } - } - - printf("thread_end %s, thread id : %lx, tid %lu\n", - "writer", pthread_self(), (unsigned long)gettid()); - return ((void*)2); -} - -int main(int argc, char **argv) -{ - int err; - pthread_t *tid_reader, *tid_writer; - void *tret; - int i; - cycles_t tot_rtime = 0; - cycles_t tot_wtime = 0; - - if (argc < 2) { - printf("Usage : %s nr_readers nr_writers\n", argv[0]); - exit(-1); - } - num_read = atoi(argv[1]); - num_write = atoi(argv[2]); - - reader_time = malloc(sizeof(*reader_time) * num_read); - writer_time = malloc(sizeof(*writer_time) * num_write); - tid_reader = malloc(sizeof(*tid_reader) * num_read); - tid_writer = malloc(sizeof(*tid_writer) * num_write); - - printf("thread %-6s, thread id : %lx, tid %lu\n", - "main", pthread_self(), (unsigned long)gettid()); - - for (i = 0; i < NR_READ; i++) { - err = pthread_create(&tid_reader[i], NULL, thr_reader, - (void *)(long)i); - if (err != 0) - exit(1); - } - for (i = 0; i < NR_WRITE; i++) { - err = pthread_create(&tid_writer[i], NULL, thr_writer, - (void *)(long)i); - if (err != 0) - exit(1); - } - - sleep(10); - - for (i = 0; i < NR_READ; i++) { - err = pthread_join(tid_reader[i], &tret); - if (err != 0) - exit(1); - tot_rtime += reader_time[i]; - } - for (i = 0; i < NR_WRITE; i++) { - err = pthread_join(tid_writer[i], &tret); - if (err != 0) - exit(1); - tot_wtime += writer_time[i]; - } - free(test_rcu_pointer); - printf("Time per read : %g cycles\n", - (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP)); - printf("Time per write : %g cycles\n", - (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP)); - - free(reader_time); - free(writer_time); - free(tid_reader); - free(tid_writer); - - return 0; -} diff --git a/tests/urcu-asm.c b/tests/urcu-asm.c deleted file mode 100644 index dd26604..0000000 --- a/tests/urcu-asm.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * urcu-asm.c - * - * Userspace RCU library - assembly dump of primitives - * - * Copyright February 2009 - Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -void show_read_lock(void) -{ - asm volatile ("/* start */"); - rcu_read_lock(); - asm volatile ("/* end */"); -} - -void show_read_unlock(void) -{ - asm volatile ("/* start */"); - rcu_read_unlock(); - asm volatile ("/* end */"); -} diff --git a/tests/urcutorture.c b/tests/urcutorture.c deleted file mode 100644 index 87f51a1..0000000 --- a/tests/urcutorture.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include -#include -#include -#include -#include "api.h" -#define _LGPL_SOURCE -#include -#include -#include -#include "rcutorture.h" diff --git a/urcu-defer-static.h b/urcu-defer-static.h deleted file mode 100644 index 593f9a8..0000000 --- a/urcu-defer-static.h +++ /dev/null @@ -1,130 +0,0 @@ -#ifndef _URCU_DEFER_STATIC_H -#define _URCU_DEFER_STATIC_H - -/* - * urcu-defer-static.h - * - * Userspace RCU header - memory reclamation. - * - * TO BE INCLUDED ONLY IN LGPL-COMPATIBLE CODE. See urcu-defer.h for linking - * dynamically with the userspace rcu reclamation library. - * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * IBM's contributions to this file may be relicensed under LGPLv2 or later. - */ - -#include -#include - -#include -#include -#include -#include - - -/* - * Number of entries in the per-thread defer queue. Must be power of 2. - */ -#define DEFER_QUEUE_SIZE (1 << 12) -#define DEFER_QUEUE_MASK (DEFER_QUEUE_SIZE - 1) - -/* - * Typically, data is aligned at least on the architecture size. - * Use lowest bit to indicate that the current callback is changing. - * Assumes that (void *)-2L is not used often. Used to encode non-aligned - * functions and non-aligned data using extra space. - * We encode the (void *)-2L fct as: -2L, fct, data. - * We encode the (void *)-2L data as: -2L, fct, data. - * Here, DQ_FCT_MARK == ~DQ_FCT_BIT. Required for the test order. - */ -#define DQ_FCT_BIT (1 << 0) -#define DQ_IS_FCT_BIT(x) ((unsigned long)(x) & DQ_FCT_BIT) -#define DQ_SET_FCT_BIT(x) \ - (x = (void *)((unsigned long)(x) | DQ_FCT_BIT)) -#define DQ_CLEAR_FCT_BIT(x) \ - (x = (void *)((unsigned long)(x) & ~DQ_FCT_BIT)) -#define DQ_FCT_MARK ((void *)(~DQ_FCT_BIT)) - -/* - * Identify a shared load. A smp_rmc() or smp_mc() should come before the load. - */ -#define _LOAD_SHARED(p) ACCESS_ONCE(p) - -/* - * Load a data from shared memory, doing a cache flush if required. - */ -#define LOAD_SHARED(p) \ - ({ \ - smp_rmc(); \ - _LOAD_SHARED(p); \ - }) - -/* - * Identify a shared store. A smp_wmc() or smp_mc() should follow the store. - */ -#define _STORE_SHARED(x, v) ({ ACCESS_ONCE(x) = (v); }) - -/* - * Store v into x, where x is located in shared memory. Performs the required - * cache flush after writing. Returns v. - */ -#define STORE_SHARED(x, v) \ - ({ \ - _STORE_SHARED(x, v); \ - smp_wmc(); \ - (v); \ - }) - -/* - * This code section can only be included in LGPL 2.1 compatible source code. - * See below for the function call wrappers which can be used in code meant to - * be only linked with the Userspace RCU library. This comes with a small - * performance degradation on the read-side due to the added function calls. - * This is required to permit relinking with newer versions of the library. - */ - -#ifdef DEBUG_RCU -#define rcu_assert(args...) assert(args) -#else -#define rcu_assert(args...) -#endif - -/* - * defer queue. - * Contains pointers. Encoded to save space when same callback is often used. - * When looking up the next item: - * - if DQ_FCT_BIT is set, set the current callback to DQ_CLEAR_FCT_BIT(ptr) - * - next element contains pointer to data. - * - else if item == DQ_FCT_MARK - * - set the current callback to next element ptr - * - following next element contains pointer to data. - * - else current element contains data - */ -struct defer_queue { - unsigned long head; /* add element at head */ - void *last_fct_in; /* last fct pointer encoded */ - unsigned long tail; /* next element to remove at tail */ - void *last_fct_out; /* last fct pointer encoded */ - void **q; - /* registry information */ - unsigned long last_head; - struct list_head list; /* list of thread queues */ -}; - -#endif /* _URCU_DEFER_STATIC_H */ diff --git a/urcu-defer.c b/urcu-defer.c deleted file mode 100644 index a38b5c0..0000000 --- a/urcu-defer.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * urcu-defer.c - * - * Userspace RCU library - batch memory reclamation - * - * Copyright (c) 2009 Mathieu Desnoyers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "urcu-defer-static.h" -/* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */ -#include "urcu-defer.h" - -#define futex(...) syscall(__NR_futex, __VA_ARGS__) -#define FUTEX_WAIT 0 -#define FUTEX_WAKE 1 - -void __attribute__((destructor)) urcu_defer_exit(void); - -extern void synchronize_rcu(void); - -/* - * urcu_defer_mutex nests inside defer_thread_mutex. - */ -static pthread_mutex_t urcu_defer_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t defer_thread_mutex = PTHREAD_MUTEX_INITIALIZER; - -static int defer_thread_futex; - -/* - * Written to only by each individual deferer. Read by both the deferer and - * the reclamation tread. - */ -static struct defer_queue __thread defer_queue; -static LIST_HEAD(registry); -static pthread_t tid_defer; - -static void internal_urcu_lock(pthread_mutex_t *mutex) -{ - int ret; - -#ifndef DISTRUST_SIGNALS_EXTREME - ret = pthread_mutex_lock(mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -#else /* #ifndef DISTRUST_SIGNALS_EXTREME */ - while ((ret = pthread_mutex_trylock(mutex)) != 0) { - if (ret != EBUSY && ret != EINTR) { - printf("ret = %d, errno = %d\n", ret, errno); - perror("Error in pthread mutex lock"); - exit(-1); - } - pthread_testcancel(); - poll(NULL,0,10); - } -#endif /* #else #ifndef DISTRUST_SIGNALS_EXTREME */ -} - -static void internal_urcu_unlock(pthread_mutex_t *mutex) -{ - int ret; - - ret = pthread_mutex_unlock(mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -/* - * Wake-up any waiting defer thread. Called from many concurrent threads. - */ -static void wake_up_defer(void) -{ - if (unlikely(uatomic_read(&defer_thread_futex) == -1)) { - uatomic_set(&defer_thread_futex, 0); - futex(&defer_thread_futex, FUTEX_WAKE, 1, - NULL, NULL, 0); - } -} - -static unsigned long rcu_defer_num_callbacks(void) -{ - unsigned long num_items = 0, head; - struct defer_queue *index; - - internal_urcu_lock(&urcu_defer_mutex); - list_for_each_entry(index, ®istry, list) { - head = LOAD_SHARED(index->head); - num_items += head - index->tail; - } - internal_urcu_unlock(&urcu_defer_mutex); - return num_items; -} - -/* - * Defer thread waiting. Single thread. - */ -static void wait_defer(void) -{ - uatomic_dec(&defer_thread_futex); - smp_mb(); /* Write futex before read queue */ - if (rcu_defer_num_callbacks()) { - smp_mb(); /* Read queue before write futex */ - /* Callbacks are queued, don't wait. */ - uatomic_set(&defer_thread_futex, 0); - } else { - smp_rmb(); /* Read queue before read futex */ - if (uatomic_read(&defer_thread_futex) == -1) - futex(&defer_thread_futex, FUTEX_WAIT, -1, - NULL, NULL, 0); - } -} - -/* - * Must be called after Q.S. is reached. - */ -static void rcu_defer_barrier_queue(struct defer_queue *queue, - unsigned long head) -{ - unsigned long i; - void (*fct)(void *p); - void *p; - - /* - * Tail is only modified when lock is held. - * Head is only modified by owner thread. - */ - - for (i = queue->tail; i != head;) { - smp_rmb(); /* read head before q[]. */ - p = LOAD_SHARED(queue->q[i++ & DEFER_QUEUE_MASK]); - if (unlikely(DQ_IS_FCT_BIT(p))) { - DQ_CLEAR_FCT_BIT(p); - queue->last_fct_out = p; - p = LOAD_SHARED(queue->q[i++ & DEFER_QUEUE_MASK]); - } else if (unlikely(p == DQ_FCT_MARK)) { - p = LOAD_SHARED(queue->q[i++ & DEFER_QUEUE_MASK]); - queue->last_fct_out = p; - p = LOAD_SHARED(queue->q[i++ & DEFER_QUEUE_MASK]); - } - fct = queue->last_fct_out; - fct(p); - } - smp_mb(); /* push tail after having used q[] */ - STORE_SHARED(queue->tail, i); -} - -static void _rcu_defer_barrier_thread(void) -{ - unsigned long head, num_items; - - head = defer_queue.head; - num_items = head - defer_queue.tail; - if (unlikely(!num_items)) - return; - synchronize_rcu(); - rcu_defer_barrier_queue(&defer_queue, head); -} - -void rcu_defer_barrier_thread(void) -{ - internal_urcu_lock(&urcu_defer_mutex); - _rcu_defer_barrier_thread(); - internal_urcu_unlock(&urcu_defer_mutex); -} - -/* - * rcu_defer_barrier - Execute all queued rcu callbacks. - * - * Execute all RCU callbacks queued before rcu_defer_barrier() execution. - * All callbacks queued on the local thread prior to a rcu_defer_barrier() call - * are guaranteed to be executed. - * Callbacks queued by other threads concurrently with rcu_defer_barrier() - * execution are not guaranteed to be executed in the current batch (could - * be left for the next batch). These callbacks queued by other threads are only - * guaranteed to be executed if there is explicit synchronization between - * the thread adding to the queue and the thread issuing the defer_barrier call. - */ - -void rcu_defer_barrier(void) -{ - struct defer_queue *index; - unsigned long num_items = 0; - - if (list_empty(®istry)) - return; - - internal_urcu_lock(&urcu_defer_mutex); - list_for_each_entry(index, ®istry, list) { - index->last_head = LOAD_SHARED(index->head); - num_items += index->last_head - index->tail; - } - if (likely(!num_items)) { - /* - * We skip the grace period because there are no queued - * callbacks to execute. - */ - goto end; - } - synchronize_rcu(); - list_for_each_entry(index, ®istry, list) - rcu_defer_barrier_queue(index, index->last_head); -end: - internal_urcu_unlock(&urcu_defer_mutex); -} - -/* - * _rcu_defer_queue - Queue a RCU callback. - */ -void _rcu_defer_queue(void (*fct)(void *p), void *p) -{ - unsigned long head, tail; - - /* - * Head is only modified by ourself. Tail can be modified by reclamation - * thread. - */ - head = defer_queue.head; - tail = LOAD_SHARED(defer_queue.tail); - - /* - * If queue is full, empty it ourself. - * Worse-case: must allow 2 supplementary entries for fct pointer. - */ - if (unlikely(head - tail >= DEFER_QUEUE_SIZE - 2)) { - assert(head - tail <= DEFER_QUEUE_SIZE); - rcu_defer_barrier_thread(); - assert(head - LOAD_SHARED(defer_queue.tail) == 0); - } - - if (unlikely(defer_queue.last_fct_in != fct)) { - defer_queue.last_fct_in = fct; - if (unlikely(DQ_IS_FCT_BIT(fct) || fct == DQ_FCT_MARK)) { - /* - * If the function to encode is not aligned or the - * marker, write DQ_FCT_MARK followed by the function - * pointer. - */ - _STORE_SHARED(defer_queue.q[head++ & DEFER_QUEUE_MASK], - DQ_FCT_MARK); - _STORE_SHARED(defer_queue.q[head++ & DEFER_QUEUE_MASK], - fct); - } else { - DQ_SET_FCT_BIT(fct); - _STORE_SHARED(defer_queue.q[head++ & DEFER_QUEUE_MASK], - fct); - } - } else { - if (unlikely(DQ_IS_FCT_BIT(p) || p == DQ_FCT_MARK)) { - /* - * If the data to encode is not aligned or the marker, - * write DQ_FCT_MARK followed by the function pointer. - */ - _STORE_SHARED(defer_queue.q[head++ & DEFER_QUEUE_MASK], - DQ_FCT_MARK); - _STORE_SHARED(defer_queue.q[head++ & DEFER_QUEUE_MASK], - fct); - } - } - _STORE_SHARED(defer_queue.q[head++ & DEFER_QUEUE_MASK], p); - smp_wmb(); /* Publish new pointer before head */ - /* Write q[] before head. */ - STORE_SHARED(defer_queue.head, head); - smp_mb(); /* Write queue head before read futex */ - /* - * Wake-up any waiting defer thread. - */ - wake_up_defer(); -} - -void *thr_defer(void *args) -{ - for (;;) { - pthread_testcancel(); - /* - * "Be green". Don't wake up the CPU if there is no RCU work - * to perform whatsoever. Aims at saving laptop battery life by - * leaving the processor in sleep state when idle. - */ - wait_defer(); - /* Sleeping after wait_defer to let many callbacks enqueue */ - poll(NULL,0,100); /* wait for 100ms */ - rcu_defer_barrier(); - } - - return NULL; -} - -/* - * library wrappers to be used by non-LGPL compatible source code. - */ - -void rcu_defer_queue(void (*fct)(void *p), void *p) -{ - _rcu_defer_queue(fct, p); -} - -static void start_defer_thread(void) -{ - int ret; - - ret = pthread_create(&tid_defer, NULL, thr_defer, NULL); - assert(!ret); -} - -static void stop_defer_thread(void) -{ - int ret; - void *tret; - - pthread_cancel(tid_defer); - wake_up_defer(); - ret = pthread_join(tid_defer, &tret); - assert(!ret); -} - -void rcu_defer_register_thread(void) -{ - int was_empty; - - assert(defer_queue.last_head == 0); - assert(defer_queue.q == NULL); - defer_queue.q = malloc(sizeof(void *) * DEFER_QUEUE_SIZE); - - internal_urcu_lock(&defer_thread_mutex); - internal_urcu_lock(&urcu_defer_mutex); - was_empty = list_empty(®istry); - list_add(&defer_queue.list, ®istry); - internal_urcu_unlock(&urcu_defer_mutex); - - if (was_empty) - start_defer_thread(); - internal_urcu_unlock(&defer_thread_mutex); -} - -void rcu_defer_unregister_thread(void) -{ - int is_empty; - - internal_urcu_lock(&defer_thread_mutex); - internal_urcu_lock(&urcu_defer_mutex); - list_del(&defer_queue.list); - _rcu_defer_barrier_thread(); - free(defer_queue.q); - defer_queue.q = NULL; - is_empty = list_empty(®istry); - internal_urcu_unlock(&urcu_defer_mutex); - - if (is_empty) - stop_defer_thread(); - internal_urcu_unlock(&defer_thread_mutex); -} - -void urcu_defer_exit(void) -{ - assert(list_empty(®istry)); -} diff --git a/urcu-defer.h b/urcu-defer.h deleted file mode 100644 index e32156c..0000000 --- a/urcu-defer.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _URCU_BATCH_H -#define _URCU_BATCH_H - -/* - * urcu-defer.h - * - * Userspace RCU header - deferred execution - * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * LGPL-compatible code should include this header with : - * - * #define _LGPL_SOURCE - * #include - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include - -/* - * Important ! - * - * Each thread queuing memory reclamation must be registered with - * rcu_defer_register_thread(). rcu_defer_unregister_thread() should be - * called before the thread exits. - * - * *NEVER* use call_rcu()/rcu_defer_queue() within a RCU read-side critical - * section, because this primitive need to call synchronize_rcu() if the thread - * queue is full. - */ - -#define call_rcu rcu_defer_queue -#define rcu_reclaim_queue(p) rcu_defer_queue(free, p) - -extern void rcu_defer_queue(void (*fct)(void *p), void *p); - -/* - * Thread registration for reclamation. - */ -extern void rcu_defer_register_thread(void); -extern void rcu_defer_unregister_thread(void); -extern void rcu_defer_barrier(void); -extern void rcu_defer_barrier_thread(void); - -#endif /* _URCU_BATCH_H */ diff --git a/urcu-qsbr-static.h b/urcu-qsbr-static.h deleted file mode 100644 index d53a1f4..0000000 --- a/urcu-qsbr-static.h +++ /dev/null @@ -1,328 +0,0 @@ -#ifndef _URCU_QSBR_STATIC_H -#define _URCU_QSBR_STATIC_H - -/* - * urcu-qsbr-static.h - * - * Userspace RCU QSBR header. - * - * TO BE INCLUDED ONLY IN LGPL-COMPATIBLE CODE. See urcu-qsbr.h for linking - * dynamically with the userspace rcu QSBR library. - * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * IBM's contributions to this file may be relicensed under LGPLv2 or later. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * Identify a shared load. A smp_rmc() or smp_mc() should come before the load. - */ -#define _LOAD_SHARED(p) ACCESS_ONCE(p) - -/* - * Load a data from shared memory, doing a cache flush if required. - */ -#define LOAD_SHARED(p) \ - ({ \ - smp_rmc(); \ - _LOAD_SHARED(p); \ - }) - -/* - * Identify a shared store. A smp_wmc() or smp_mc() should follow the store. - */ -#define _STORE_SHARED(x, v) ({ ACCESS_ONCE(x) = (v); }) - -/* - * Store v into x, where x is located in shared memory. Performs the required - * cache flush after writing. Returns v. - */ -#define STORE_SHARED(x, v) \ - ({ \ - _STORE_SHARED(x, v); \ - smp_wmc(); \ - (v); \ - }) - -/** - * _rcu_dereference - reads (copy) a RCU-protected pointer to a local variable - * into a RCU read-side critical section. The pointer can later be safely - * dereferenced within the critical section. - * - * This ensures that the pointer copy is invariant thorough the whole critical - * section. - * - * Inserts memory barriers on architectures that require them (currently only - * Alpha) and documents which pointers are protected by RCU. - * - * Should match rcu_assign_pointer() or rcu_xchg_pointer(). - */ - -#define _rcu_dereference(p) ({ \ - typeof(p) _________p1 = LOAD_SHARED(p); \ - smp_read_barrier_depends(); \ - (_________p1); \ - }) - -#define futex(...) syscall(__NR_futex, __VA_ARGS__) -#define FUTEX_WAIT 0 -#define FUTEX_WAKE 1 - -/* - * This code section can only be included in LGPL 2.1 compatible source code. - * See below for the function call wrappers which can be used in code meant to - * be only linked with the Userspace RCU library. This comes with a small - * performance degradation on the read-side due to the added function calls. - * This is required to permit relinking with newer versions of the library. - */ - -/* - * If a reader is really non-cooperative and refuses to commit its - * urcu_reader.ctr count to memory (there is no barrier in the reader - * per-se), kick it after a few loops waiting for it. - */ -#define KICK_READER_LOOPS 10000 - -/* - * Active attempts to check for reader Q.S. before calling futex(). - */ -#define RCU_QS_ACTIVE_ATTEMPTS 100 - -#ifdef DEBUG_RCU -#define rcu_assert(args...) assert(args) -#else -#define rcu_assert(args...) -#endif - -#ifdef DEBUG_YIELD -#include -#include -#include -#include - -#define YIELD_READ (1 << 0) -#define YIELD_WRITE (1 << 1) - -/* maximum sleep delay, in us */ -#define MAX_SLEEP 50 - -extern unsigned int yield_active; -extern unsigned int __thread rand_yield; - -static inline void debug_yield_read(void) -{ - if (yield_active & YIELD_READ) - if (rand_r(&rand_yield) & 0x1) - usleep(rand_r(&rand_yield) % MAX_SLEEP); -} - -static inline void debug_yield_write(void) -{ - if (yield_active & YIELD_WRITE) - if (rand_r(&rand_yield) & 0x1) - usleep(rand_r(&rand_yield) % MAX_SLEEP); -} - -static inline void debug_yield_init(void) -{ - rand_yield = time(NULL) ^ pthread_self(); -} -#else -static inline void debug_yield_read(void) -{ -} - -static inline void debug_yield_write(void) -{ -} - -static inline void debug_yield_init(void) -{ - -} -#endif - -static inline void reader_barrier() -{ - smp_mb(); -} - -#define RCU_GP_ONLINE (1UL << 0) -#define RCU_GP_CTR (1UL << 1) - -/* - * Global quiescent period counter with low-order bits unused. - * Using a int rather than a char to eliminate false register dependencies - * causing stalls on some architectures. - */ -extern unsigned long urcu_gp_ctr; - -struct urcu_reader { - /* Data used by both reader and synchronize_rcu() */ - unsigned long ctr; - /* Data used for registry */ - struct list_head head __attribute__((aligned(CACHE_LINE_SIZE))); - pthread_t tid; -}; - -extern struct urcu_reader __thread urcu_reader; - -extern int gp_futex; - -/* - * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. - */ -static inline void wake_up_gp(void) -{ - if (unlikely(uatomic_read(&gp_futex) == -1)) { - uatomic_set(&gp_futex, 0); - futex(&gp_futex, FUTEX_WAKE, 1, - NULL, NULL, 0); - } -} - -#if (BITS_PER_LONG < 64) -static inline int rcu_gp_ongoing(unsigned long *value) -{ - unsigned long reader_gp; - - if (value == NULL) - return 0; - reader_gp = LOAD_SHARED(*value); - return reader_gp && ((reader_gp ^ urcu_gp_ctr) & RCU_GP_CTR); -} -#else /* !(BITS_PER_LONG < 64) */ -static inline int rcu_gp_ongoing(unsigned long *value) -{ - unsigned long reader_gp; - - if (value == NULL) - return 0; - reader_gp = LOAD_SHARED(*value); - return reader_gp && (reader_gp - urcu_gp_ctr > ULONG_MAX / 2); -} -#endif /* !(BITS_PER_LONG < 64) */ - -static inline void _rcu_read_lock(void) -{ - rcu_assert(urcu_reader.ctr); -} - -static inline void _rcu_read_unlock(void) -{ -} - -static inline void _rcu_quiescent_state(void) -{ - smp_mb(); - _STORE_SHARED(urcu_reader.ctr, _LOAD_SHARED(urcu_gp_ctr)); - smp_mb(); /* write urcu_reader.ctr before read futex */ - wake_up_gp(); - smp_mb(); -} - -static inline void _rcu_thread_offline(void) -{ - smp_mb(); - STORE_SHARED(urcu_reader.ctr, 0); - smp_mb(); /* write urcu_reader.ctr before read futex */ - wake_up_gp(); -} - -static inline void _rcu_thread_online(void) -{ - _STORE_SHARED(urcu_reader.ctr, LOAD_SHARED(urcu_gp_ctr)); - smp_mb(); -} - -/** - * _rcu_assign_pointer - assign (publicize) a pointer to a new data structure - * meant to be read by RCU read-side critical sections. Returns the assigned - * value. - * - * Documents which pointers will be dereferenced by RCU read-side critical - * sections and adds the required memory barriers on architectures requiring - * them. It also makes sure the compiler does not reorder code initializing the - * data structure before its publication. - * - * Should match rcu_dereference_pointer(). - */ - -#define _rcu_assign_pointer(p, v) \ - ({ \ - if (!__builtin_constant_p(v) || \ - ((v) != NULL)) \ - wmb(); \ - STORE_SHARED(p, v); \ - }) - -/** - * _rcu_cmpxchg_pointer - same as rcu_assign_pointer, but tests if the pointer - * is as expected by "old". If succeeds, returns the previous pointer to the - * data structure, which can be safely freed after waiting for a quiescent state - * using synchronize_rcu(). If fails (unexpected value), returns old (which - * should not be freed !). - */ - -#define _rcu_cmpxchg_pointer(p, old, _new) \ - ({ \ - if (!__builtin_constant_p(_new) || \ - ((_new) != NULL)) \ - wmb(); \ - uatomic_cmpxchg(p, old, _new); \ - }) - -/** - * _rcu_xchg_pointer - same as rcu_assign_pointer, but returns the previous - * pointer to the data structure, which can be safely freed after waiting for a - * quiescent state using synchronize_rcu(). - */ - -#define _rcu_xchg_pointer(p, v) \ - ({ \ - if (!__builtin_constant_p(v) || \ - ((v) != NULL)) \ - wmb(); \ - uatomic_xchg(p, v); \ - }) - -/* - * Exchanges the pointer and waits for quiescent state. - * The pointer returned can be freed. - */ -#define _rcu_publish_content(p, v) \ - ({ \ - void *oldptr; \ - oldptr = _rcu_xchg_pointer(p, v); \ - synchronize_rcu(); \ - oldptr; \ - }) - -#endif /* _URCU_QSBR_STATIC_H */ diff --git a/urcu-qsbr.c b/urcu-qsbr.c deleted file mode 100644 index f002c34..0000000 --- a/urcu-qsbr.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * urcu-qsbr.c - * - * Userspace RCU QSBR library - * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * IBM's contributions to this file may be relicensed under LGPLv2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define BUILD_QSBR_LIB -#include "urcu-qsbr-static.h" -/* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */ -#include "urcu-qsbr.h" - -void __attribute__((destructor)) rcu_exit(void); - -static pthread_mutex_t urcu_mutex = PTHREAD_MUTEX_INITIALIZER; - -int gp_futex; - -/* - * Global grace period counter. - */ -unsigned long urcu_gp_ctr = RCU_GP_ONLINE; - -/* - * Written to only by each individual reader. Read by both the reader and the - * writers. - */ -struct urcu_reader __thread urcu_reader; - -#ifdef DEBUG_YIELD -unsigned int yield_active; -unsigned int __thread rand_yield; -#endif - -static LIST_HEAD(registry); - -static void internal_urcu_lock(void) -{ - int ret; - -#ifndef DISTRUST_SIGNALS_EXTREME - ret = pthread_mutex_lock(&urcu_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -#else /* #ifndef DISTRUST_SIGNALS_EXTREME */ - while ((ret = pthread_mutex_trylock(&urcu_mutex)) != 0) { - if (ret != EBUSY && ret != EINTR) { - printf("ret = %d, errno = %d\n", ret, errno); - perror("Error in pthread mutex lock"); - exit(-1); - } - poll(NULL,0,10); - } -#endif /* #else #ifndef DISTRUST_SIGNALS_EXTREME */ -} - -static void internal_urcu_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&urcu_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -/* - * synchronize_rcu() waiting. Single thread. - */ -static void wait_gp(void) -{ - /* Read reader_gp before read futex */ - smp_rmb(); - if (uatomic_read(&gp_futex) == -1) - futex(&gp_futex, FUTEX_WAIT, -1, - NULL, NULL, 0); -} - -static void wait_for_quiescent_state(void) -{ - LIST_HEAD(qsreaders); - int wait_loops = 0; - struct urcu_reader *index, *tmp; - - if (list_empty(®istry)) - return; - /* - * Wait for each thread rcu_reader_qs_gp count to become 0. - */ - for (;;) { - wait_loops++; - if (wait_loops == RCU_QS_ACTIVE_ATTEMPTS) { - uatomic_dec(&gp_futex); - /* Write futex before read reader_gp */ - smp_mb(); - } - - list_for_each_entry_safe(index, tmp, ®istry, head) { - if (!rcu_gp_ongoing(&index->ctr)) - list_move(&index->head, &qsreaders); - } - - if (list_empty(®istry)) { - if (wait_loops == RCU_QS_ACTIVE_ATTEMPTS) { - /* Read reader_gp before write futex */ - smp_mb(); - uatomic_set(&gp_futex, 0); - } - break; - } else { - if (wait_loops == RCU_QS_ACTIVE_ATTEMPTS) { - wait_gp(); - } else { -#ifndef HAS_INCOHERENT_CACHES - cpu_relax(); -#else /* #ifndef HAS_INCOHERENT_CACHES */ - smp_mb(); -#endif /* #else #ifndef HAS_INCOHERENT_CACHES */ - } - } - } - /* put back the reader list in the registry */ - list_splice(&qsreaders, ®istry); -} - -/* - * Using a two-subphases algorithm for architectures with smaller than 64-bit - * long-size to ensure we do not encounter an overflow bug. - */ - -#if (BITS_PER_LONG < 64) -/* - * called with urcu_mutex held. - */ -static void switch_next_urcu_qparity(void) -{ - STORE_SHARED(urcu_gp_ctr, urcu_gp_ctr ^ RCU_GP_CTR); -} - -void synchronize_rcu(void) -{ - unsigned long was_online; - - was_online = urcu_reader.ctr; - - /* All threads should read qparity before accessing data structure - * where new ptr points to. - */ - /* Write new ptr before changing the qparity */ - smp_mb(); - - /* - * Mark the writer thread offline to make sure we don't wait for - * our own quiescent state. This allows using synchronize_rcu() in - * threads registered as readers. - */ - if (was_online) - STORE_SHARED(urcu_reader.ctr, 0); - - internal_urcu_lock(); - - switch_next_urcu_qparity(); /* 0 -> 1 */ - - /* - * Must commit qparity update to memory before waiting for parity - * 0 quiescent state. Failure to do so could result in the writer - * waiting forever while new readers are always accessing data (no - * progress). - * Ensured by STORE_SHARED and LOAD_SHARED. - */ - - /* - * Wait for previous parity to be empty of readers. - */ - wait_for_quiescent_state(); /* Wait readers in parity 0 */ - - /* - * Must finish waiting for quiescent state for parity 0 before - * committing qparity update to memory. Failure to do so could result in - * the writer waiting forever while new readers are always accessing - * data (no progress). - * Ensured by STORE_SHARED and LOAD_SHARED. - */ - - switch_next_urcu_qparity(); /* 1 -> 0 */ - - /* - * Must commit qparity update to memory before waiting for parity - * 1 quiescent state. Failure to do so could result in the writer - * waiting forever while new readers are always accessing data (no - * progress). - * Ensured by STORE_SHARED and LOAD_SHARED. - */ - - /* - * Wait for previous parity to be empty of readers. - */ - wait_for_quiescent_state(); /* Wait readers in parity 1 */ - - internal_urcu_unlock(); - - /* - * Finish waiting for reader threads before letting the old ptr being - * freed. - */ - if (was_online) - _STORE_SHARED(urcu_reader.ctr, LOAD_SHARED(urcu_gp_ctr)); - smp_mb(); -} -#else /* !(BITS_PER_LONG < 64) */ -void synchronize_rcu(void) -{ - unsigned long was_online; - - was_online = urcu_reader.ctr; - - /* - * Mark the writer thread offline to make sure we don't wait for - * our own quiescent state. This allows using synchronize_rcu() in - * threads registered as readers. - */ - smp_mb(); - if (was_online) - STORE_SHARED(urcu_reader.ctr, 0); - - internal_urcu_lock(); - STORE_SHARED(urcu_gp_ctr, urcu_gp_ctr + RCU_GP_CTR); - wait_for_quiescent_state(); - internal_urcu_unlock(); - - if (was_online) - _STORE_SHARED(urcu_reader.ctr, LOAD_SHARED(urcu_gp_ctr)); - smp_mb(); -} -#endif /* !(BITS_PER_LONG < 64) */ - -/* - * library wrappers to be used by non-LGPL compatible source code. - */ - -void rcu_read_lock(void) -{ - _rcu_read_lock(); -} - -void rcu_read_unlock(void) -{ - _rcu_read_unlock(); -} - -void *rcu_dereference(void *p) -{ - return _rcu_dereference(p); -} - -void *rcu_assign_pointer_sym(void **p, void *v) -{ - wmb(); - return STORE_SHARED(p, v); -} - -void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new) -{ - wmb(); - return uatomic_cmpxchg(p, old, _new); -} - -void *rcu_xchg_pointer_sym(void **p, void *v) -{ - wmb(); - return uatomic_xchg(p, v); -} - -void *rcu_publish_content_sym(void **p, void *v) -{ - void *oldptr; - - oldptr = _rcu_xchg_pointer(p, v); - synchronize_rcu(); - return oldptr; -} - -void rcu_quiescent_state(void) -{ - _rcu_quiescent_state(); -} - -void rcu_thread_offline(void) -{ - _rcu_thread_offline(); -} - -void rcu_thread_online(void) -{ - _rcu_thread_online(); -} - -void rcu_register_thread(void) -{ - urcu_reader.tid = pthread_self(); - assert(urcu_reader.ctr == 0); - - internal_urcu_lock(); - list_add(&urcu_reader.head, ®istry); - internal_urcu_unlock(); - _rcu_thread_online(); -} - -void rcu_unregister_thread(void) -{ - /* - * We have to make the thread offline otherwise we end up dealocking - * with a waiting writer. - */ - _rcu_thread_offline(); - internal_urcu_lock(); - list_del(&urcu_reader.head); - internal_urcu_unlock(); -} - -void rcu_exit(void) -{ - assert(list_empty(®istry)); -} diff --git a/urcu-qsbr.h b/urcu-qsbr.h deleted file mode 100644 index fdf4712..0000000 --- a/urcu-qsbr.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef _URCU_QSBR_H -#define _URCU_QSBR_H - -/* - * urcu-qsbr.h - * - * Userspace RCU QSBR header. - * - * LGPL-compatible code should include this header with : - * - * #define _LGPL_SOURCE - * #include - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * IBM's contributions to this file may be relicensed under LGPLv2 or later. - */ - -#include -#include - -/* - * Important ! - * - * Each thread containing read-side critical sections must be registered - * with rcu_register_thread() before calling rcu_read_lock(). - * rcu_unregister_thread() should be called before the thread exits. - */ - -#ifdef _LGPL_SOURCE - -#include - -/* - * Mappings for static use of the userspace RCU library. - * Should only be used in LGPL-compatible code. - */ - -#define rcu_dereference _rcu_dereference -#define rcu_read_lock _rcu_read_lock -#define rcu_read_unlock _rcu_read_unlock - -#define rcu_quiescent_state _rcu_quiescent_state -#define rcu_thread_offline _rcu_thread_offline -#define rcu_thread_online _rcu_thread_online - -#define rcu_assign_pointer _rcu_assign_pointer -#define rcu_cmpxchg_pointer _rcu_cmpxchg_pointer -#define rcu_xchg_pointer _rcu_xchg_pointer -#define rcu_publish_content _rcu_publish_content - -#else /* !_LGPL_SOURCE */ - -/* - * library wrappers to be used by non-LGPL compatible source code. - */ - -/* - * QSBR read lock/unlock are guaranteed to be no-ops. Therefore, we expose them - * in the LGPL header for any code to use. However, the debug version is not - * nops and may contain sanity checks. To activate it, applications must be - * recompiled with -DURCU_DEBUG (even non-LGPL/GPL applications). This is the - * best trade-off between license/performance/code triviality and - * library debugging & tracing features we could come up with. - */ - -#if (!defined(BUILD_QSBR_LIB) && defined(URCU_DEBUG)) - -static inline void rcu_read_lock(void) -{ -} - -static inline void rcu_read_lock(void) -{ -} - -#else /* !URCU_DEBUG */ - -extern void rcu_read_lock(void); -extern void rcu_read_unlock(void); - -#endif /* !URCU_DEBUG */ - -extern void *rcu_dereference(void *p); - -extern void rcu_quiescent_state(void); -extern void rcu_thread_offline(void); -extern void rcu_thread_online(void); - -extern void *rcu_assign_pointer_sym(void **p, void *v); - -#define rcu_assign_pointer(p, v) \ - rcu_assign_pointer_sym((void **)(p), (v)) - -extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new); -#define rcu_cmpxchg_pointer(p, old, _new) \ - rcu_cmpxchg_pointer_sym((void **)(p), (old), (_new)) - -extern void *rcu_xchg_pointer_sym(void **p, void *v); -#define rcu_xchg_pointer(p, v) \ - rcu_xchg_pointer_sym((void **)(p), (v)) - -extern void *rcu_publish_content_sym(void **p, void *v); -#define rcu_publish_content(p, v) \ - rcu_publish_content_sym((void **)(p), (v)) - -#endif /* !_LGPL_SOURCE */ - -extern void synchronize_rcu(void); - -/* - * Reader thread registration. - */ -extern void rcu_register_thread(void); -extern void rcu_unregister_thread(void); - -#endif /* _URCU_QSBR_H */ diff --git a/urcu-static.h b/urcu-static.h deleted file mode 100644 index 7d6d7ac..0000000 --- a/urcu-static.h +++ /dev/null @@ -1,364 +0,0 @@ -#ifndef _URCU_STATIC_H -#define _URCU_STATIC_H - -/* - * urcu-static.h - * - * Userspace RCU header. - * - * TO BE INCLUDED ONLY IN LGPL-COMPATIBLE CODE. See urcu.h for linking - * dynamically with the userspace rcu library. - * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * IBM's contributions to this file may be relicensed under LGPLv2 or later. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * Identify a shared load. A smp_rmc() or smp_mc() should come before the load. - */ -#define _LOAD_SHARED(p) ACCESS_ONCE(p) - -/* - * Load a data from shared memory, doing a cache flush if required. - */ -#define LOAD_SHARED(p) \ - ({ \ - smp_rmc(); \ - _LOAD_SHARED(p); \ - }) - -/* - * Identify a shared store. A smp_wmc() or smp_mc() should follow the store. - */ -#define _STORE_SHARED(x, v) ({ ACCESS_ONCE(x) = (v); }) - -/* - * Store v into x, where x is located in shared memory. Performs the required - * cache flush after writing. Returns v. - */ -#define STORE_SHARED(x, v) \ - ({ \ - _STORE_SHARED(x, v); \ - smp_wmc(); \ - (v); \ - }) - -/** - * _rcu_dereference - reads (copy) a RCU-protected pointer to a local variable - * into a RCU read-side critical section. The pointer can later be safely - * dereferenced within the critical section. - * - * This ensures that the pointer copy is invariant thorough the whole critical - * section. - * - * Inserts memory barriers on architectures that require them (currently only - * Alpha) and documents which pointers are protected by RCU. - * - * The compiler memory barrier in LOAD_SHARED() ensures that value-speculative - * optimizations (e.g. VSS: Value Speculation Scheduling) does not perform the - * data read before the pointer read by speculating the value of the pointer. - * Correct ordering is ensured because the pointer is read as a volatile access. - * This acts as a global side-effect operation, which forbids reordering of - * dependent memory operations. Note that such concern about dependency-breaking - * optimizations will eventually be taken care of by the "memory_order_consume" - * addition to forthcoming C++ standard. - * - * Should match rcu_assign_pointer() or rcu_xchg_pointer(). - */ - -#define _rcu_dereference(p) ({ \ - typeof(p) _________p1 = LOAD_SHARED(p); \ - smp_read_barrier_depends(); \ - (_________p1); \ - }) - -#define futex(...) syscall(__NR_futex, __VA_ARGS__) -#define FUTEX_WAIT 0 -#define FUTEX_WAKE 1 - -/* - * This code section can only be included in LGPL 2.1 compatible source code. - * See below for the function call wrappers which can be used in code meant to - * be only linked with the Userspace RCU library. This comes with a small - * performance degradation on the read-side due to the added function calls. - * This is required to permit relinking with newer versions of the library. - */ - -/* - * The signal number used by the RCU library can be overridden with - * -DSIGURCU= when compiling the library. - */ -#ifndef SIGURCU -#define SIGURCU SIGUSR1 -#endif - -/* - * If a reader is really non-cooperative and refuses to commit its - * urcu_active_readers count to memory (there is no barrier in the reader - * per-se), kick it after a few loops waiting for it. - */ -#define KICK_READER_LOOPS 10000 - -/* - * Active attempts to check for reader Q.S. before calling futex(). - */ -#define RCU_QS_ACTIVE_ATTEMPTS 100 - -#ifdef DEBUG_RCU -#define rcu_assert(args...) assert(args) -#else -#define rcu_assert(args...) -#endif - -#ifdef DEBUG_YIELD -#include -#include -#include -#include - -#define YIELD_READ (1 << 0) -#define YIELD_WRITE (1 << 1) - -/* - * Updates without URCU_MB are much slower. Account this in - * the delay. - */ -#ifdef URCU_MB -/* maximum sleep delay, in us */ -#define MAX_SLEEP 50 -#else -#define MAX_SLEEP 30000 -#endif - -extern unsigned int yield_active; -extern unsigned int __thread rand_yield; - -static inline void debug_yield_read(void) -{ - if (yield_active & YIELD_READ) - if (rand_r(&rand_yield) & 0x1) - usleep(rand_r(&rand_yield) % MAX_SLEEP); -} - -static inline void debug_yield_write(void) -{ - if (yield_active & YIELD_WRITE) - if (rand_r(&rand_yield) & 0x1) - usleep(rand_r(&rand_yield) % MAX_SLEEP); -} - -static inline void debug_yield_init(void) -{ - rand_yield = time(NULL) ^ pthread_self(); -} -#else -static inline void debug_yield_read(void) -{ -} - -static inline void debug_yield_write(void) -{ -} - -static inline void debug_yield_init(void) -{ - -} -#endif - -#ifdef URCU_MB -static inline void reader_barrier() -{ - smp_mb(); -} -#else -static inline void reader_barrier() -{ - barrier(); -} -#endif - -/* - * The trick here is that RCU_GP_CTR_BIT must be a multiple of 8 so we can use a - * full 8-bits, 16-bits or 32-bits bitmask for the lower order bits. - */ -#define RCU_GP_COUNT (1UL << 0) -/* Use the amount of bits equal to half of the architecture long size */ -#define RCU_GP_CTR_BIT (1UL << (sizeof(long) << 2)) -#define RCU_GP_CTR_NEST_MASK (RCU_GP_CTR_BIT - 1) - -/* - * Global quiescent period counter with low-order bits unused. - * Using a int rather than a char to eliminate false register dependencies - * causing stalls on some architectures. - */ -extern long urcu_gp_ctr; - -struct urcu_reader { - /* Data used by both reader and synchronize_rcu() */ - long ctr; - char need_mb; - /* Data used for registry */ - struct list_head head __attribute__((aligned(CACHE_LINE_SIZE))); - pthread_t tid; -}; - -extern struct urcu_reader __thread urcu_reader; - -extern int gp_futex; - -/* - * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. - */ -static inline void wake_up_gp(void) -{ - if (unlikely(uatomic_read(&gp_futex) == -1)) { - uatomic_set(&gp_futex, 0); - futex(&gp_futex, FUTEX_WAKE, 1, - NULL, NULL, 0); - } -} - -static inline int rcu_old_gp_ongoing(long *value) -{ - long v; - - if (value == NULL) - return 0; - /* - * Make sure both tests below are done on the same version of *value - * to insure consistency. - */ - v = LOAD_SHARED(*value); - return (v & RCU_GP_CTR_NEST_MASK) && - ((v ^ urcu_gp_ctr) & RCU_GP_CTR_BIT); -} - -static inline void _rcu_read_lock(void) -{ - long tmp; - - tmp = urcu_reader.ctr; - /* urcu_gp_ctr = RCU_GP_COUNT | (~RCU_GP_CTR_BIT or RCU_GP_CTR_BIT) */ - if (likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { - _STORE_SHARED(urcu_reader.ctr, _LOAD_SHARED(urcu_gp_ctr)); - /* - * Set active readers count for outermost nesting level before - * accessing the pointer. See force_mb_all_threads(). - */ - reader_barrier(); - } else { - _STORE_SHARED(urcu_reader.ctr, tmp + RCU_GP_COUNT); - } -} - -static inline void _rcu_read_unlock(void) -{ - long tmp; - - tmp = urcu_reader.ctr; - /* - * Finish using rcu before decrementing the pointer. - * See force_mb_all_threads(). - */ - if (likely((tmp & RCU_GP_CTR_NEST_MASK) == RCU_GP_COUNT)) { - reader_barrier(); - _STORE_SHARED(urcu_reader.ctr, urcu_reader.ctr - RCU_GP_COUNT); - /* write urcu_reader.ctr before read futex */ - reader_barrier(); - wake_up_gp(); - } else { - _STORE_SHARED(urcu_reader.ctr, urcu_reader.ctr - RCU_GP_COUNT); - } -} - -/** - * _rcu_assign_pointer - assign (publicize) a pointer to a new data structure - * meant to be read by RCU read-side critical sections. Returns the assigned - * value. - * - * Documents which pointers will be dereferenced by RCU read-side critical - * sections and adds the required memory barriers on architectures requiring - * them. It also makes sure the compiler does not reorder code initializing the - * data structure before its publication. - * - * Should match rcu_dereference_pointer(). - */ - -#define _rcu_assign_pointer(p, v) \ - ({ \ - if (!__builtin_constant_p(v) || \ - ((v) != NULL)) \ - wmb(); \ - STORE_SHARED(p, v); \ - }) - -/** - * _rcu_cmpxchg_pointer - same as rcu_assign_pointer, but tests if the pointer - * is as expected by "old". If succeeds, returns the previous pointer to the - * data structure, which can be safely freed after waiting for a quiescent state - * using synchronize_rcu(). If fails (unexpected value), returns old (which - * should not be freed !). - */ - -#define _rcu_cmpxchg_pointer(p, old, _new) \ - ({ \ - if (!__builtin_constant_p(_new) || \ - ((_new) != NULL)) \ - wmb(); \ - uatomic_cmpxchg(p, old, _new); \ - }) - -/** - * _rcu_xchg_pointer - same as rcu_assign_pointer, but returns the previous - * pointer to the data structure, which can be safely freed after waiting for a - * quiescent state using synchronize_rcu(). - */ - -#define _rcu_xchg_pointer(p, v) \ - ({ \ - if (!__builtin_constant_p(v) || \ - ((v) != NULL)) \ - wmb(); \ - uatomic_xchg(p, v); \ - }) - -/* - * Exchanges the pointer and waits for quiescent state. - * The pointer returned can be freed. - */ -#define _rcu_publish_content(p, v) \ - ({ \ - void *oldptr; \ - oldptr = _rcu_xchg_pointer(p, v); \ - synchronize_rcu(); \ - oldptr; \ - }) - -#endif /* _URCU_STATIC_H */ diff --git a/urcu.c b/urcu.c deleted file mode 100644 index 7fdb1a6..0000000 --- a/urcu.c +++ /dev/null @@ -1,479 +0,0 @@ -/* - * urcu.c - * - * Userspace RCU library - * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * IBM's contributions to this file may be relicensed under LGPLv2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "urcu-static.h" -/* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */ -#include "urcu.h" - -#ifndef URCU_MB -static int init_done; - -void __attribute__((constructor)) urcu_init(void); -void __attribute__((destructor)) urcu_exit(void); -#else -void urcu_init(void) -{ -} -#endif - -static pthread_mutex_t urcu_mutex = PTHREAD_MUTEX_INITIALIZER; - -int gp_futex; - -/* - * Global grace period counter. - * Contains the current RCU_GP_CTR_BIT. - * Also has a RCU_GP_COUNT of 1, to accelerate the reader fast path. - * Written to only by writer with mutex taken. Read by both writer and readers. - */ -long urcu_gp_ctr = RCU_GP_COUNT; - -/* - * Written to only by each individual reader. Read by both the reader and the - * writers. - */ -struct urcu_reader __thread urcu_reader; - -#ifdef DEBUG_YIELD -unsigned int yield_active; -unsigned int __thread rand_yield; -#endif - -static LIST_HEAD(registry); - -static void internal_urcu_lock(void) -{ - int ret; - -#ifndef DISTRUST_SIGNALS_EXTREME - ret = pthread_mutex_lock(&urcu_mutex); - if (ret) { - perror("Error in pthread mutex lock"); - exit(-1); - } -#else /* #ifndef DISTRUST_SIGNALS_EXTREME */ - while ((ret = pthread_mutex_trylock(&urcu_mutex)) != 0) { - if (ret != EBUSY && ret != EINTR) { - printf("ret = %d, errno = %d\n", ret, errno); - perror("Error in pthread mutex lock"); - exit(-1); - } - if (urcu_reader.need_mb) { - smp_mb(); - urcu_reader.need_mb = 0; - smp_mb(); - } - poll(NULL,0,10); - } -#endif /* #else #ifndef DISTRUST_SIGNALS_EXTREME */ -} - -static void internal_urcu_unlock(void) -{ - int ret; - - ret = pthread_mutex_unlock(&urcu_mutex); - if (ret) { - perror("Error in pthread mutex unlock"); - exit(-1); - } -} - -/* - * called with urcu_mutex held. - */ -static void switch_next_urcu_qparity(void) -{ - STORE_SHARED(urcu_gp_ctr, urcu_gp_ctr ^ RCU_GP_CTR_BIT); -} - -#ifdef URCU_MB -#if 0 /* unused */ -static void force_mb_single_thread(struct urcu_reader *index) -{ - smp_mb(); -} -#endif //0 - -static void force_mb_all_threads(void) -{ - smp_mb(); -} -#else /* #ifdef URCU_MB */ -#if 0 /* unused */ -static void force_mb_single_thread(struct urcu_reader *index) -{ - assert(!list_empty(®istry)); - /* - * pthread_kill has a smp_mb(). But beware, we assume it performs - * a cache flush on architectures with non-coherent cache. Let's play - * safe and don't assume anything : we use smp_mc() to make sure the - * cache flush is enforced. - */ - index->need_mb = 1; - smp_mc(); /* write ->need_mb before sending the signals */ - pthread_kill(index->tid, SIGURCU); - smp_mb(); - /* - * Wait for sighandler (and thus mb()) to execute on every thread. - * BUSY-LOOP. - */ - while (index->need_mb) { - poll(NULL, 0, 1); - } - smp_mb(); /* read ->need_mb before ending the barrier */ -} -#endif //0 - -static void force_mb_all_threads(void) -{ - struct urcu_reader *index; - - /* - * Ask for each threads to execute a smp_mb() so we can consider the - * compiler barriers around rcu read lock as real memory barriers. - */ - if (list_empty(®istry)) - return; - /* - * pthread_kill has a smp_mb(). But beware, we assume it performs - * a cache flush on architectures with non-coherent cache. Let's play - * safe and don't assume anything : we use smp_mc() to make sure the - * cache flush is enforced. - */ - list_for_each_entry(index, ®istry, head) { - index->need_mb = 1; - smp_mc(); /* write need_mb before sending the signal */ - pthread_kill(index->tid, SIGURCU); - } - /* - * Wait for sighandler (and thus mb()) to execute on every thread. - * - * Note that the pthread_kill() will never be executed on systems - * that correctly deliver signals in a timely manner. However, it - * is not uncommon for kernels to have bugs that can result in - * lost or unduly delayed signals. - * - * If you are seeing the below pthread_kill() executing much at - * all, we suggest testing the underlying kernel and filing the - * relevant bug report. For Linux kernels, we recommend getting - * the Linux Test Project (LTP). - */ - list_for_each_entry(index, ®istry, head) { - while (index->need_mb) { - pthread_kill(index->tid, SIGURCU); - poll(NULL, 0, 1); - } - } - smp_mb(); /* read ->need_mb before ending the barrier */ -} -#endif /* #else #ifdef URCU_MB */ - -/* - * synchronize_rcu() waiting. Single thread. - */ -static void wait_gp(void) -{ - /* Read reader_gp before read futex */ - force_mb_all_threads(); - if (uatomic_read(&gp_futex) == -1) - futex(&gp_futex, FUTEX_WAIT, -1, - NULL, NULL, 0); -} - -void wait_for_quiescent_state(void) -{ - LIST_HEAD(qsreaders); - int wait_loops = 0; - struct urcu_reader *index, *tmp; - - if (list_empty(®istry)) - return; - /* - * Wait for each thread urcu_reader.ctr count to become 0. - */ - for (;;) { - wait_loops++; - if (wait_loops == RCU_QS_ACTIVE_ATTEMPTS) { - uatomic_dec(&gp_futex); - /* Write futex before read reader_gp */ - force_mb_all_threads(); - } - - list_for_each_entry_safe(index, tmp, ®istry, head) { - if (!rcu_old_gp_ongoing(&index->ctr)) - list_move(&index->head, &qsreaders); - } - -#ifndef HAS_INCOHERENT_CACHES - if (list_empty(®istry)) { - if (wait_loops == RCU_QS_ACTIVE_ATTEMPTS) { - /* Read reader_gp before write futex */ - force_mb_all_threads(); - uatomic_set(&gp_futex, 0); - } - break; - } else { - if (wait_loops == RCU_QS_ACTIVE_ATTEMPTS) - wait_gp(); - else - cpu_relax(); - } -#else /* #ifndef HAS_INCOHERENT_CACHES */ - /* - * BUSY-LOOP. Force the reader thread to commit its - * urcu_reader.ctr update to memory if we wait for too long. - */ - if (list_empty(®istry)) { - if (wait_loops == RCU_QS_ACTIVE_ATTEMPTS) { - /* Read reader_gp before write futex */ - force_mb_all_threads(); - uatomic_set(&gp_futex, 0); - } - break; - } else { - switch (wait_loops) { - case RCU_QS_ACTIVE_ATTEMPTS: - wait_gp(); - break; /* only escape switch */ - case KICK_READER_LOOPS: - force_mb_all_threads(); - wait_loops = 0; - break; /* only escape switch */ - default: - cpu_relax(); - } - } -#endif /* #else #ifndef HAS_INCOHERENT_CACHES */ - } - /* put back the reader list in the registry */ - list_splice(&qsreaders, ®istry); -} - -void synchronize_rcu(void) -{ - internal_urcu_lock(); - - /* All threads should read qparity before accessing data structure - * where new ptr points to. Must be done within internal_urcu_lock - * because it iterates on reader threads.*/ - /* Write new ptr before changing the qparity */ - force_mb_all_threads(); - - switch_next_urcu_qparity(); /* 0 -> 1 */ - - /* - * Must commit qparity update to memory before waiting for parity - * 0 quiescent state. Failure to do so could result in the writer - * waiting forever while new readers are always accessing data (no - * progress). - * Ensured by STORE_SHARED and LOAD_SHARED. - */ - - /* - * Adding a smp_mb() which is _not_ formally required, but makes the - * model easier to understand. It does not have a big performance impact - * anyway, given this is the write-side. - */ - smp_mb(); - - /* - * Wait for previous parity to be empty of readers. - */ - wait_for_quiescent_state(); /* Wait readers in parity 0 */ - - /* - * Must finish waiting for quiescent state for parity 0 before - * committing qparity update to memory. Failure to do so could result in - * the writer waiting forever while new readers are always accessing - * data (no progress). - * Ensured by STORE_SHARED and LOAD_SHARED. - */ - - /* - * Adding a smp_mb() which is _not_ formally required, but makes the - * model easier to understand. It does not have a big performance impact - * anyway, given this is the write-side. - */ - smp_mb(); - - switch_next_urcu_qparity(); /* 1 -> 0 */ - - /* - * Must commit qparity update to memory before waiting for parity - * 1 quiescent state. Failure to do so could result in the writer - * waiting forever while new readers are always accessing data (no - * progress). - * Ensured by STORE_SHARED and LOAD_SHARED. - */ - - /* - * Adding a smp_mb() which is _not_ formally required, but makes the - * model easier to understand. It does not have a big performance impact - * anyway, given this is the write-side. - */ - smp_mb(); - - /* - * Wait for previous parity to be empty of readers. - */ - wait_for_quiescent_state(); /* Wait readers in parity 1 */ - - /* Finish waiting for reader threads before letting the old ptr being - * freed. Must be done within internal_urcu_lock because it iterates on - * reader threads. */ - force_mb_all_threads(); - - internal_urcu_unlock(); -} - -/* - * library wrappers to be used by non-LGPL compatible source code. - */ - -void rcu_read_lock(void) -{ - _rcu_read_lock(); -} - -void rcu_read_unlock(void) -{ - _rcu_read_unlock(); -} - -void *rcu_dereference(void *p) -{ - return _rcu_dereference(p); -} - -void *rcu_assign_pointer_sym(void **p, void *v) -{ - wmb(); - return STORE_SHARED(p, v); -} - -void *rcu_xchg_pointer_sym(void **p, void *v) -{ - wmb(); - return uatomic_xchg(p, v); -} - -void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new) -{ - wmb(); - return uatomic_cmpxchg(p, old, _new); -} - -void *rcu_publish_content_sym(void **p, void *v) -{ - void *oldptr; - - oldptr = _rcu_xchg_pointer(p, v); - synchronize_rcu(); - return oldptr; -} - -void rcu_register_thread(void) -{ - urcu_reader.tid = pthread_self(); - assert(urcu_reader.need_mb == 0); - assert(urcu_reader.ctr == 0); - - internal_urcu_lock(); - urcu_init(); /* In case gcc does not support constructor attribute */ - list_add(&urcu_reader.head, ®istry); - internal_urcu_unlock(); -} - -void rcu_unregister_thread(void) -{ - internal_urcu_lock(); - list_del(&urcu_reader.head); - internal_urcu_unlock(); -} - -#ifndef URCU_MB -static void sigurcu_handler(int signo, siginfo_t *siginfo, void *context) -{ - /* - * Executing this smp_mb() is the only purpose of this signal handler. - * It punctually promotes barrier() into smp_mb() on every thread it is - * executed on. - */ - smp_mb(); - urcu_reader.need_mb = 0; - smp_mb(); -} - -/* - * urcu_init constructor. Called when the library is linked, but also when - * reader threads are calling rcu_register_thread(). - * Should only be called by a single thread at a given time. This is ensured by - * holing the internal_urcu_lock() from rcu_register_thread() or by running at - * library load time, which should not be executed by multiple threads nor - * concurrently with rcu_register_thread() anyway. - */ -void urcu_init(void) -{ - struct sigaction act; - int ret; - - if (init_done) - return; - init_done = 1; - - act.sa_sigaction = sigurcu_handler; - act.sa_flags = SA_SIGINFO | SA_RESTART; - sigemptyset(&act.sa_mask); - ret = sigaction(SIGURCU, &act, NULL); - if (ret) { - perror("Error in sigaction"); - exit(-1); - } -} - -void urcu_exit(void) -{ - struct sigaction act; - int ret; - - ret = sigaction(SIGURCU, NULL, &act); - if (ret) { - perror("Error in sigaction"); - exit(-1); - } - assert(act.sa_sigaction == sigurcu_handler); - assert(list_empty(®istry)); -} -#endif /* #ifndef URCU_MB */ diff --git a/urcu.h b/urcu.h deleted file mode 100644 index 9d4cd3c..0000000 --- a/urcu.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef _URCU_H -#define _URCU_H - -/* - * urcu.h - * - * Userspace RCU header - * - * Copyright (c) 2009 Mathieu Desnoyers - * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. - * - * LGPL-compatible code should include this header with : - * - * #define _LGPL_SOURCE - * #include - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * IBM's contributions to this file may be relicensed under LGPLv2 or later. - */ - -#include -#include - -/* - * Important ! - * - * Each thread containing read-side critical sections must be registered - * with rcu_register_thread() before calling rcu_read_lock(). - * rcu_unregister_thread() should be called before the thread exits. - */ - -#ifdef _LGPL_SOURCE - -#include - -/* - * Mappings for static use of the userspace RCU library. - * Should only be used in LGPL-compatible code. - */ - -#define rcu_dereference _rcu_dereference -#define rcu_read_lock _rcu_read_lock -#define rcu_read_unlock _rcu_read_unlock - -#define rcu_assign_pointer _rcu_assign_pointer -#define rcu_cmpxchg_pointer _rcu_cmpxchg_pointer -#define rcu_xchg_pointer _rcu_xchg_pointer -#define rcu_publish_content _rcu_publish_content - -#else /* !_LGPL_SOURCE */ - -/* - * library wrappers to be used by non-LGPL compatible source code. - */ - -extern void rcu_read_lock(void); -extern void rcu_read_unlock(void); - -extern void *rcu_dereference(void *p); - -extern void *rcu_assign_pointer_sym(void **p, void *v); - -#define rcu_assign_pointer(p, v) \ - rcu_assign_pointer_sym((void **)(p), (v)) - -extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new); -#define rcu_cmpxchg_pointer(p, old, _new) \ - rcu_cmpxchg_pointer_sym((void **)(p), (old), (_new)) - -extern void *rcu_xchg_pointer_sym(void **p, void *v); -#define rcu_xchg_pointer(p, v) \ - rcu_xchg_pointer_sym((void **)(p), (v)) - -extern void *rcu_publish_content_sym(void **p, void *v); -#define rcu_publish_content(p, v) \ - rcu_publish_content_sym((void **)(p), (v)) - -#endif /* !_LGPL_SOURCE */ - -extern void synchronize_rcu(void); - -/* - * Reader thread registration. - */ -extern void rcu_register_thread(void); -extern void rcu_unregister_thread(void); - -/* - * Explicit urcu initialization, for "early" use within library constructors. - */ -extern void urcu_init(void); - -#endif /* _URCU_H */