mirror of
https://salsa.debian.org/ha-team/libqb
synced 2026-08-08 20:07:21 +00:00
Imported Upstream version 0.11.1
This commit is contained in:
commit
85f75e9d49
1
.tarball-version
Normal file
1
.tarball-version
Normal file
@ -0,0 +1 @@
|
||||
0.11.1
|
||||
458
COPYING
Normal file
458
COPYING
Normal file
@ -0,0 +1,458 @@
|
||||
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
|
||||
57
INSTALL
Normal file
57
INSTALL
Normal file
@ -0,0 +1,57 @@
|
||||
----------------------------------------------
|
||||
The Quarterback library Installation Guide
|
||||
----------------------------------------------
|
||||
Please read LICENSE for a description of the licensing of this software.
|
||||
|
||||
---------------------------------
|
||||
* Platforms Built and Tested On *
|
||||
---------------------------------
|
||||
Quarterback has been tested on:
|
||||
Linux: Fedora 12
|
||||
OpenSolaris
|
||||
BSD: FreeBSD
|
||||
MacOSX: Darwin latest update
|
||||
|
||||
It should build and run properly on the tested platforms as well as possibly
|
||||
others with minimal effort. Quarterback requires a coherent mmap() system call
|
||||
and will not operate on platforms which don't support coherent mmap().
|
||||
|
||||
----------------------------
|
||||
* Building from git *
|
||||
----------------------------
|
||||
When building and installing from subversion, automake 2.61 or later is
|
||||
required. Prior versions will result in build failures.
|
||||
|
||||
Step 1: check out a copy of the repository
|
||||
git clone git://git.fedoraprojects.org/git/quarterback
|
||||
|
||||
Find the version you want to build. Usually this will be the "master"
|
||||
branch. If you want to build a specific released
|
||||
version check 'git tag -l'.
|
||||
|
||||
Step 2: Generate the makefiles
|
||||
balance: ./autogen.sh
|
||||
|
||||
Step 3: Run the configure script
|
||||
balance: ./configure
|
||||
|
||||
Step 4: build
|
||||
balance: make
|
||||
|
||||
Step 5: Install the binaries
|
||||
balance: sudo make install
|
||||
|
||||
-------------------------
|
||||
* Building from tarball *
|
||||
-------------------------
|
||||
The tarball is distributed with pregenerated makefiles. There is no need
|
||||
to run the autogen.sh script in this case.
|
||||
|
||||
Step 1: Run the configure script
|
||||
balance:~/quarterback% ./configure
|
||||
|
||||
Step 2: Install the binaries
|
||||
balance:~/quarterback% su
|
||||
balance:~/quarterback# make install
|
||||
|
||||
|
||||
134
Makefile.am
Normal file
134
Makefile.am
Normal file
@ -0,0 +1,134 @@
|
||||
# Copyright (C) 2010 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Andrew Beekhof <abeekhof@redhat.com>
|
||||
# Steven Dake <sdake@redhat.com>
|
||||
# Angus Salkeld <asalkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
SPEC = $(PACKAGE_NAME).spec
|
||||
|
||||
TARFILE = $(PACKAGE_NAME)-$(VERSION).tar.gz
|
||||
|
||||
EXTRA_DIST = autogen.sh $(SPEC).in \
|
||||
build-aux/git-version-gen \
|
||||
build-aux/gitlog-to-changelog \
|
||||
build-aux/release.mk \
|
||||
.version
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure depcomp \
|
||||
config.guess config.sub missing install-sh \
|
||||
autoheader automake autoconf libtool libtoolize \
|
||||
ltmain.sh compile
|
||||
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
dist_doc_DATA = COPYING INSTALL README.markdown
|
||||
|
||||
SUBDIRS = include lib docs tests examples
|
||||
|
||||
doxygen:
|
||||
$(MAKE) -C docs doxygen
|
||||
|
||||
dist-clean-local:
|
||||
$(AM_V_GEN)rm -f autoconf automake autoheader
|
||||
|
||||
maintainer-clean-local:
|
||||
$(AM_V_GEN)rm -rf m4
|
||||
$(AM_V_GEN)rm -f .version .tarball-version
|
||||
|
||||
clean-generic:
|
||||
$(AM_V_GEN)rm -rf $(SPEC) $(TARFILE)
|
||||
|
||||
## make rpm/srpm section.
|
||||
|
||||
$(SPEC): $(SPEC).in
|
||||
$(AM_V_GEN)rm -f $@-t $@
|
||||
LC_ALL=C date="$(shell date "+%a %b %d %Y")" && \
|
||||
if [ -f .tarball-version ]; then \
|
||||
gitver="$(shell cat .tarball-version)" && \
|
||||
rpmver=$$gitver && \
|
||||
alphatag="" && \
|
||||
dirty="" && \
|
||||
numcomm="0"; \
|
||||
else \
|
||||
gitver="$(shell git describe --abbrev=4 --match='v*' HEAD 2>/dev/null)" && \
|
||||
rpmver=`echo $$gitver | sed -e "s/^v//" -e "s/-.*//g"` && \
|
||||
alphatag=`echo $$gitver | sed -e "s/.*-//" -e "s/^g//"` && \
|
||||
vtag=`echo $$gitver | sed -e "s/-.*//g"` && \
|
||||
numcomm=`git rev-list $$vtag..HEAD | wc -l` && \
|
||||
git update-index --refresh > /dev/null 2>&1 || true && \
|
||||
dirty=`git diff-index --name-only HEAD 2>/dev/null`; \
|
||||
fi && \
|
||||
if [ -n "$$dirty" ]; then dirty="dirty"; else dirty=""; fi && \
|
||||
if [ "$$numcomm" = "0" ]; then \
|
||||
sed \
|
||||
-e "s#@version@#$$rpmver#g" \
|
||||
-e "s#%glo.*alpha.*##g" \
|
||||
-e "s#%glo.*numcomm.*##g" \
|
||||
-e "s#@dirty@#$$dirty#g" \
|
||||
-e "s#@date@#$$date#g" \
|
||||
$< > $@-t; \
|
||||
else \
|
||||
sed \
|
||||
-e "s#@version@#$$rpmver#g" \
|
||||
-e "s#@alphatag@#$$alphatag#g" \
|
||||
-e "s#@numcomm@#$$numcomm#g" \
|
||||
-e "s#@dirty@#$$dirty#g" \
|
||||
-e "s#@date@#$$date#g" \
|
||||
$< > $@-t; \
|
||||
fi; \
|
||||
if [ -z "$$dirty" ]; then sed -i -e "s#%glo.*dirty.*##g" $@-t; fi
|
||||
$(AM_V_GEN)chmod a-w $@-t
|
||||
$(AM_V_GEN)mv $@-t $@
|
||||
|
||||
$(TARFILE):
|
||||
$(MAKE) dist
|
||||
|
||||
RPMBUILDOPTS = --define "_sourcedir $(abs_builddir)" \
|
||||
--define "_specdir $(abs_builddir)" \
|
||||
--define "_builddir $(abs_builddir)" \
|
||||
--define "_srcrpmdir $(abs_builddir)" \
|
||||
--define "_rpmdir $(abs_builddir)"
|
||||
|
||||
srpm: clean
|
||||
$(MAKE) $(SPEC) $(TARFILE)
|
||||
rpmbuild $(RPMBUILDOPTS) --nodeps -bs $(SPEC)
|
||||
|
||||
rpm: clean
|
||||
$(MAKE) $(SPEC) $(TARFILE)
|
||||
rpmbuild $(RPMBUILDOPTS) -ba $(SPEC)
|
||||
|
||||
# release/versioning
|
||||
BUILT_SOURCES = .version
|
||||
.version:
|
||||
echo $(VERSION) > $@-t && mv $@-t $@
|
||||
|
||||
dist-hook: gen-ChangeLog
|
||||
echo $(VERSION) > $(distdir)/.tarball-version
|
||||
|
||||
gen_start_date = 2000-01-01
|
||||
.PHONY: gen-ChangeLog
|
||||
gen-ChangeLog:
|
||||
if test -d .git; then \
|
||||
$(top_srcdir)/build-aux/gitlog-to-changelog \
|
||||
--since=$(gen_start_date) > $(distdir)/cl-t; \
|
||||
rm -f $(distdir)/ChangeLog; \
|
||||
mv $(distdir)/cl-t $(distdir)/ChangeLog; \
|
||||
fi
|
||||
936
Makefile.in
Normal file
936
Makefile.in
Normal file
@ -0,0 +1,936 @@
|
||||
# Makefile.in generated by automake 1.11.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# Copyright (C) 2010 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Andrew Beekhof <abeekhof@redhat.com>
|
||||
# Steven Dake <sdake@redhat.com>
|
||||
# Angus Salkeld <asalkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = .
|
||||
DIST_COMMON = $(am__configure_deps) $(dist_doc_DATA) \
|
||||
$(srcdir)/Makefile.am $(srcdir)/Makefile.in \
|
||||
$(top_srcdir)/configure COPYING INSTALL compile config.guess \
|
||||
config.sub depcomp install-sh ltmain.sh missing
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
configure.lineno config.status.lineno
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/include/config.h \
|
||||
$(top_builddir)/include/qb/qbconfig.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
|
||||
html-recursive info-recursive install-data-recursive \
|
||||
install-dvi-recursive install-exec-recursive \
|
||||
install-html-recursive install-info-recursive \
|
||||
install-pdf-recursive install-ps-recursive install-recursive \
|
||||
installcheck-recursive installdirs-recursive pdf-recursive \
|
||||
ps-recursive uninstall-recursive
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(docdir)"
|
||||
DATA = $(dist_doc_DATA)
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
|
||||
$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
|
||||
distdir dist dist-all distcheck
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
am__remove_distdir = \
|
||||
if test -d "$(distdir)"; then \
|
||||
find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
&& rm -rf "$(distdir)" \
|
||||
|| { sleep 5 && rm -rf "$(distdir)"; }; \
|
||||
else :; fi
|
||||
am__relativize = \
|
||||
dir0=`pwd`; \
|
||||
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
|
||||
sed_rest='s,^[^/]*/*,,'; \
|
||||
sed_last='s,^.*/\([^/]*\)$$,\1,'; \
|
||||
sed_butlast='s,/*[^/]*$$,,'; \
|
||||
while test -n "$$dir1"; do \
|
||||
first=`echo "$$dir1" | sed -e "$$sed_first"`; \
|
||||
if test "$$first" != "."; then \
|
||||
if test "$$first" = ".."; then \
|
||||
dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
|
||||
dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
|
||||
else \
|
||||
first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
|
||||
if test "$$first2" = "$$first"; then \
|
||||
dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
|
||||
else \
|
||||
dir2="../$$dir2"; \
|
||||
fi; \
|
||||
dir0="$$dir0"/"$$first"; \
|
||||
fi; \
|
||||
fi; \
|
||||
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
|
||||
done; \
|
||||
reldir="$$dir2"
|
||||
DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.xz
|
||||
GZIP_ENV = --best
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
|
||||
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CHECK_CFLAGS = @CHECK_CFLAGS@
|
||||
CHECK_LIBS = @CHECK_LIBS@
|
||||
CP = @CP@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DOXYGEN = @DOXYGEN@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GLIB_CFLAGS = @GLIB_CFLAGS@
|
||||
GLIB_LIBS = @GLIB_LIBS@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIB_RT = @LIB_RT@
|
||||
LINT_FLAGS = @LINT_FLAGS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKGCONFIG = @PKGCONFIG@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
SOCKETDIR = @SOCKETDIR@
|
||||
SPLINT = @SPLINT@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
SPEC = $(PACKAGE_NAME).spec
|
||||
TARFILE = $(PACKAGE_NAME)-$(VERSION).tar.gz
|
||||
EXTRA_DIST = autogen.sh $(SPEC).in \
|
||||
build-aux/git-version-gen \
|
||||
build-aux/gitlog-to-changelog \
|
||||
build-aux/release.mk \
|
||||
.version
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure depcomp \
|
||||
config.guess config.sub missing install-sh \
|
||||
autoheader automake autoconf libtool libtoolize \
|
||||
ltmain.sh compile
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
dist_doc_DATA = COPYING INSTALL README.markdown
|
||||
SUBDIRS = include lib docs tests examples
|
||||
RPMBUILDOPTS = --define "_sourcedir $(abs_builddir)" \
|
||||
--define "_specdir $(abs_builddir)" \
|
||||
--define "_builddir $(abs_builddir)" \
|
||||
--define "_srcrpmdir $(abs_builddir)" \
|
||||
--define "_rpmdir $(abs_builddir)"
|
||||
|
||||
|
||||
# release/versioning
|
||||
BUILT_SOURCES = .version
|
||||
gen_start_date = 2000-01-01
|
||||
all: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
am--refresh: Makefile
|
||||
@:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
|
||||
$(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
echo ' $(SHELL) ./config.status'; \
|
||||
$(SHELL) ./config.status;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
$(am__cd) $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
distclean-libtool:
|
||||
-rm -f libtool config.lt
|
||||
install-dist_docDATA: $(dist_doc_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)"
|
||||
@list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
|
||||
done
|
||||
|
||||
uninstall-dist_docDATA:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
|
||||
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
|
||||
dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
|
||||
|
||||
# This directory's subdirectories are mostly independent; you can cd
|
||||
# into them and run `make' without going through this Makefile.
|
||||
# To change the values of `make' variables: instead of editing Makefiles,
|
||||
# (1) if the variable is set in `config.status', edit `config.status'
|
||||
# (which will cause the Makefiles to be regenerated when you run `make');
|
||||
# (2) otherwise, pass the desired values on the `make' command line.
|
||||
$(RECURSIVE_TARGETS):
|
||||
@fail= failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
dot_seen=yes; \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done; \
|
||||
if test "$$dot_seen" = "no"; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
|
||||
fi; test -z "$$fail"
|
||||
|
||||
$(RECURSIVE_CLEAN_TARGETS):
|
||||
@fail= failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
case "$@" in \
|
||||
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
|
||||
*) list='$(SUBDIRS)' ;; \
|
||||
esac; \
|
||||
rev=''; for subdir in $$list; do \
|
||||
if test "$$subdir" = "."; then :; else \
|
||||
rev="$$subdir $$rev"; \
|
||||
fi; \
|
||||
done; \
|
||||
rev="$$rev ."; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
for subdir in $$rev; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done && test -z "$$fail"
|
||||
tags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
|
||||
done
|
||||
ctags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
|
||||
done
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
|
||||
include_option=--etags-include; \
|
||||
empty_fix=.; \
|
||||
else \
|
||||
include_option=--include; \
|
||||
empty_fix=; \
|
||||
fi; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test ! -f $$subdir/TAGS || \
|
||||
set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
|
||||
fi; \
|
||||
done; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
$(am__remove_distdir)
|
||||
test -d "$(distdir)" || mkdir "$(distdir)"
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test -d "$(distdir)/$$subdir" \
|
||||
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
|
||||
$(am__relativize); \
|
||||
new_distdir=$$reldir; \
|
||||
dir1=$$subdir; dir2="$(top_distdir)"; \
|
||||
$(am__relativize); \
|
||||
new_top_distdir=$$reldir; \
|
||||
echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
|
||||
echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
|
||||
($(am__cd) $$subdir && \
|
||||
$(MAKE) $(AM_MAKEFLAGS) \
|
||||
top_distdir="$$new_top_distdir" \
|
||||
distdir="$$new_distdir" \
|
||||
am__remove_distdir=: \
|
||||
am__skip_length_check=: \
|
||||
am__skip_mode_fix=: \
|
||||
distdir) \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
$(MAKE) $(AM_MAKEFLAGS) \
|
||||
top_distdir="$(top_distdir)" distdir="$(distdir)" \
|
||||
dist-hook
|
||||
-test -n "$(am__skip_mode_fix)" \
|
||||
|| find "$(distdir)" -type d ! -perm -755 \
|
||||
-exec chmod u+rwx,go+rx {} \; -o \
|
||||
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|
||||
|| chmod -R a+r "$(distdir)"
|
||||
dist-gzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-lzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-lzma: distdir
|
||||
tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
|
||||
$(am__remove_distdir)
|
||||
dist-xz: distdir
|
||||
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-tarZ: distdir
|
||||
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-shar: distdir
|
||||
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-zip: distdir
|
||||
-rm -f $(distdir).zip
|
||||
zip -rq $(distdir).zip $(distdir)
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist dist-all: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
|
||||
$(am__remove_distdir)
|
||||
|
||||
# This target untars the dist file and tries a VPATH configuration. Then
|
||||
# it guarantees that the distribution is self-contained by making another
|
||||
# tarfile.
|
||||
distcheck: dist
|
||||
case '$(DIST_ARCHIVES)' in \
|
||||
*.tar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
|
||||
*.tar.bz2*) \
|
||||
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.lzma*) \
|
||||
lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
|
||||
*.tar.lz*) \
|
||||
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
|
||||
*.tar.xz*) \
|
||||
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
|
||||
*.tar.Z*) \
|
||||
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
|
||||
*.shar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
|
||||
*.zip*) \
|
||||
unzip $(distdir).zip ;;\
|
||||
esac
|
||||
chmod -R a-w $(distdir); chmod a+w $(distdir)
|
||||
mkdir $(distdir)/_build
|
||||
mkdir $(distdir)/_inst
|
||||
chmod a-w $(distdir)
|
||||
test -d $(distdir)/_build || exit 0; \
|
||||
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
|
||||
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
|
||||
&& am__cwd=`pwd` \
|
||||
&& $(am__cd) $(distdir)/_build \
|
||||
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
|
||||
$(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) check \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
|
||||
distuninstallcheck \
|
||||
&& chmod -R a-w "$$dc_install_base" \
|
||||
&& ({ \
|
||||
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
|
||||
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
|
||||
} || { rm -rf "$$dc_destdir"; exit 1; }) \
|
||||
&& rm -rf "$$dc_destdir" \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dist \
|
||||
&& rm -rf $(DIST_ARCHIVES) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
|
||||
&& cd "$$am__cwd" \
|
||||
|| exit 1
|
||||
$(am__remove_distdir)
|
||||
@(echo "$(distdir) archives ready for distribution: "; \
|
||||
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
|
||||
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
|
||||
distuninstallcheck:
|
||||
@test -n '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: trying to run $@ with an empty' \
|
||||
'$$(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
$(am__cd) '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left after uninstall:" ; \
|
||||
if test -n "$(DESTDIR)"; then \
|
||||
echo " (check DESTDIR support)"; \
|
||||
fi ; \
|
||||
$(distuninstallcheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
distcleancheck: distclean
|
||||
@if test '$(srcdir)' = . ; then \
|
||||
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
|
||||
exit 1 ; \
|
||||
fi
|
||||
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left in build directory after distclean:" ; \
|
||||
$(distcleancheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
check-am: all-am
|
||||
check: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) check-recursive
|
||||
all-am: Makefile $(DATA)
|
||||
installdirs: installdirs-recursive
|
||||
installdirs-am:
|
||||
for dir in "$(DESTDIR)$(docdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) install-recursive
|
||||
install-exec: install-exec-recursive
|
||||
install-data: install-data-recursive
|
||||
uninstall: uninstall-recursive
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-recursive
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
|
||||
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
|
||||
clean: clean-recursive
|
||||
|
||||
clean-am: clean-generic clean-libtool mostlyclean-am
|
||||
|
||||
distclean: distclean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic distclean-libtool \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-recursive
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-recursive
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-recursive
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-dist_docDATA
|
||||
|
||||
install-dvi: install-dvi-recursive
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-recursive
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-recursive
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-recursive
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-recursive
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf $(top_srcdir)/autom4te.cache
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic \
|
||||
maintainer-clean-local
|
||||
|
||||
mostlyclean: mostlyclean-recursive
|
||||
|
||||
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
|
||||
|
||||
pdf: pdf-recursive
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-recursive
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-dist_docDATA
|
||||
|
||||
.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check \
|
||||
ctags-recursive install install-am install-strip \
|
||||
tags-recursive
|
||||
|
||||
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
|
||||
all all-am am--refresh check check-am clean clean-generic \
|
||||
clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \
|
||||
dist-gzip dist-hook dist-lzip dist-lzma dist-shar dist-tarZ \
|
||||
dist-xz dist-zip distcheck distclean distclean-generic \
|
||||
distclean-libtool distclean-tags distcleancheck distdir \
|
||||
distuninstallcheck dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am \
|
||||
install-dist_docDATA install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-man install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs installdirs-am maintainer-clean \
|
||||
maintainer-clean-generic maintainer-clean-local mostlyclean \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-recursive uninstall uninstall-am \
|
||||
uninstall-dist_docDATA
|
||||
|
||||
|
||||
doxygen:
|
||||
$(MAKE) -C docs doxygen
|
||||
|
||||
dist-clean-local:
|
||||
$(AM_V_GEN)rm -f autoconf automake autoheader
|
||||
|
||||
maintainer-clean-local:
|
||||
$(AM_V_GEN)rm -rf m4
|
||||
$(AM_V_GEN)rm -f .version .tarball-version
|
||||
|
||||
clean-generic:
|
||||
$(AM_V_GEN)rm -rf $(SPEC) $(TARFILE)
|
||||
|
||||
$(SPEC): $(SPEC).in
|
||||
$(AM_V_GEN)rm -f $@-t $@
|
||||
LC_ALL=C date="$(shell date "+%a %b %d %Y")" && \
|
||||
if [ -f .tarball-version ]; then \
|
||||
gitver="$(shell cat .tarball-version)" && \
|
||||
rpmver=$$gitver && \
|
||||
alphatag="" && \
|
||||
dirty="" && \
|
||||
numcomm="0"; \
|
||||
else \
|
||||
gitver="$(shell git describe --abbrev=4 --match='v*' HEAD 2>/dev/null)" && \
|
||||
rpmver=`echo $$gitver | sed -e "s/^v//" -e "s/-.*//g"` && \
|
||||
alphatag=`echo $$gitver | sed -e "s/.*-//" -e "s/^g//"` && \
|
||||
vtag=`echo $$gitver | sed -e "s/-.*//g"` && \
|
||||
numcomm=`git rev-list $$vtag..HEAD | wc -l` && \
|
||||
git update-index --refresh > /dev/null 2>&1 || true && \
|
||||
dirty=`git diff-index --name-only HEAD 2>/dev/null`; \
|
||||
fi && \
|
||||
if [ -n "$$dirty" ]; then dirty="dirty"; else dirty=""; fi && \
|
||||
if [ "$$numcomm" = "0" ]; then \
|
||||
sed \
|
||||
-e "s#@version@#$$rpmver#g" \
|
||||
-e "s#%glo.*alpha.*##g" \
|
||||
-e "s#%glo.*numcomm.*##g" \
|
||||
-e "s#@dirty@#$$dirty#g" \
|
||||
-e "s#@date@#$$date#g" \
|
||||
$< > $@-t; \
|
||||
else \
|
||||
sed \
|
||||
-e "s#@version@#$$rpmver#g" \
|
||||
-e "s#@alphatag@#$$alphatag#g" \
|
||||
-e "s#@numcomm@#$$numcomm#g" \
|
||||
-e "s#@dirty@#$$dirty#g" \
|
||||
-e "s#@date@#$$date#g" \
|
||||
$< > $@-t; \
|
||||
fi; \
|
||||
if [ -z "$$dirty" ]; then sed -i -e "s#%glo.*dirty.*##g" $@-t; fi
|
||||
$(AM_V_GEN)chmod a-w $@-t
|
||||
$(AM_V_GEN)mv $@-t $@
|
||||
|
||||
$(TARFILE):
|
||||
$(MAKE) dist
|
||||
|
||||
srpm: clean
|
||||
$(MAKE) $(SPEC) $(TARFILE)
|
||||
rpmbuild $(RPMBUILDOPTS) --nodeps -bs $(SPEC)
|
||||
|
||||
rpm: clean
|
||||
$(MAKE) $(SPEC) $(TARFILE)
|
||||
rpmbuild $(RPMBUILDOPTS) -ba $(SPEC)
|
||||
.version:
|
||||
echo $(VERSION) > $@-t && mv $@-t $@
|
||||
|
||||
dist-hook: gen-ChangeLog
|
||||
echo $(VERSION) > $(distdir)/.tarball-version
|
||||
.PHONY: gen-ChangeLog
|
||||
gen-ChangeLog:
|
||||
if test -d .git; then \
|
||||
$(top_srcdir)/build-aux/gitlog-to-changelog \
|
||||
--since=$(gen_start_date) > $(distdir)/cl-t; \
|
||||
rm -f $(distdir)/ChangeLog; \
|
||||
mv $(distdir)/cl-t $(distdir)/ChangeLog; \
|
||||
fi
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
47
README.markdown
Normal file
47
README.markdown
Normal file
@ -0,0 +1,47 @@
|
||||
# libqb
|
||||
|
||||
## What is libqb?
|
||||
libqb is a library with the primary purpose of providing high performance
|
||||
client server reusable features. It provides high performance logging,
|
||||
tracing, ipc, and poll.
|
||||
|
||||
We don't intend be an all encompassing library, but instead provide very
|
||||
specially focused APIs that are highly tuned for maximum performance for client/server applications.
|
||||
|
||||
## For more information look at:
|
||||
* [Our wiki](https://github.com/asalkeld/libqb/wiki)
|
||||
* [Issues/Bugs](https://github.com/asalkeld/libqb/issues)
|
||||
* [The doxygen generated manual](http://libqb.org/html/doxygen/)
|
||||
* You can build it yourself with the following commands:
|
||||
|
||||
$ make doxygen
|
||||
$ firefox ./doc/html/index.html
|
||||
|
||||
## Dependencies
|
||||
* glib-2.0-devel (If you want to build the glib example code)
|
||||
* check-devel (If you want to run the tests)
|
||||
* doxygen and graphviz (If you want to build the doxygen man pages or html manual)
|
||||
|
||||
## Source Control (GIT)
|
||||
|
||||
git clone git://github.com/asalkeld/libqb.git
|
||||
|
||||
[See Github](https://github.com/asalkeld/libqb)
|
||||
|
||||
## Installing from source
|
||||
|
||||
$ ./autogen.sh
|
||||
$ ./configure
|
||||
$ make
|
||||
$ sudo make install
|
||||
|
||||
## How you can help
|
||||
If you find this project useful, you may want to consider supporting its future development.
|
||||
There are a number of ways to support the project.
|
||||
|
||||
* Test and report issues.
|
||||
* Help others on the [mailing list](https://fedorahosted.org/mailman/listinfo/quarterback-devel).
|
||||
* Contribute documentation, examples and test cases.
|
||||
* Contribute patches.
|
||||
* Spread the word.
|
||||
|
||||
1226
aclocal.m4
vendored
Normal file
1226
aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4
autogen.sh
Executable file
4
autogen.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
# Run this to generate all the initial makefiles, etc.
|
||||
mkdir -p m4
|
||||
autoreconf -i -v && echo Now run ./configure and make
|
||||
172
build-aux/git-version-gen
Executable file
172
build-aux/git-version-gen
Executable file
@ -0,0 +1,172 @@
|
||||
#!/bin/sh
|
||||
# Print a version string.
|
||||
scriptversion=2011-02-19.19; # UTC
|
||||
|
||||
# Copyright (C) 2007-2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
|
||||
# It may be run two ways:
|
||||
# - from a git repository in which the "git describe" command below
|
||||
# produces useful output (thus requiring at least one signed tag)
|
||||
# - from a non-git-repo directory containing a .tarball-version file, which
|
||||
# presumes this script is invoked like "./git-version-gen .tarball-version".
|
||||
|
||||
# In order to use intra-version strings in your project, you will need two
|
||||
# separate generated version string files:
|
||||
#
|
||||
# .tarball-version - present only in a distribution tarball, and not in
|
||||
# a checked-out repository. Created with contents that were learned at
|
||||
# the last time autoconf was run, and used by git-version-gen. Must not
|
||||
# be present in either $(srcdir) or $(builddir) for git-version-gen to
|
||||
# give accurate answers during normal development with a checked out tree,
|
||||
# but must be present in a tarball when there is no version control system.
|
||||
# Therefore, it cannot be used in any dependencies. GNUmakefile has
|
||||
# hooks to force a reconfigure at distribution time to get the value
|
||||
# correct, without penalizing normal development with extra reconfigures.
|
||||
#
|
||||
# .version - present in a checked-out repository and in a distribution
|
||||
# tarball. Usable in dependencies, particularly for files that don't
|
||||
# want to depend on config.h but do want to track version changes.
|
||||
# Delete this file prior to any autoconf run where you want to rebuild
|
||||
# files to pick up a version string change; and leave it stale to
|
||||
# minimize rebuild time after unrelated changes to configure sources.
|
||||
#
|
||||
# It is probably wise to add these two files to .gitignore, so that you
|
||||
# don't accidentally commit either generated file.
|
||||
#
|
||||
# Use the following line in your configure.ac, so that $(VERSION) will
|
||||
# automatically be up-to-date each time configure is run (and note that
|
||||
# since configure.ac no longer includes a version string, Makefile rules
|
||||
# should not depend on configure.ac for version updates).
|
||||
#
|
||||
# AC_INIT([GNU project],
|
||||
# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
|
||||
# [bug-project@example])
|
||||
#
|
||||
# Then use the following lines in your Makefile.am, so that .version
|
||||
# will be present for dependencies, and so that .tarball-version will
|
||||
# exist in distribution tarballs.
|
||||
#
|
||||
# BUILT_SOURCES = $(top_srcdir)/.version
|
||||
# $(top_srcdir)/.version:
|
||||
# echo $(VERSION) > $@-t && mv $@-t $@
|
||||
# dist-hook:
|
||||
# echo $(VERSION) > $(distdir)/.tarball-version
|
||||
|
||||
case $# in
|
||||
1|2) ;;
|
||||
*) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version" \
|
||||
'[TAG-NORMALIZATION-SED-SCRIPT]'
|
||||
exit 1;;
|
||||
esac
|
||||
|
||||
tarball_version_file=$1
|
||||
tag_sed_script="${2:-s/x/x/}"
|
||||
nl='
|
||||
'
|
||||
|
||||
# Avoid meddling by environment variable of the same name.
|
||||
v=
|
||||
v_from_git=
|
||||
|
||||
# First see if there is a tarball-only version file.
|
||||
# then try "git describe", then default.
|
||||
if test -f $tarball_version_file
|
||||
then
|
||||
v=`cat $tarball_version_file` || v=
|
||||
case $v in
|
||||
*$nl*) v= ;; # reject multi-line output
|
||||
[0-9]*) ;;
|
||||
*) v= ;;
|
||||
esac
|
||||
test -z "$v" \
|
||||
&& echo "$0: WARNING: $tarball_version_file is missing or damaged" 1>&2
|
||||
fi
|
||||
|
||||
if test -n "$v"
|
||||
then
|
||||
: # use $v
|
||||
# Otherwise, if there is at least one git commit involving the working
|
||||
# directory, and "git describe" output looks sensible, use that to
|
||||
# derive a version string.
|
||||
elif test "`git log -1 --pretty=format:x . 2>&1`" = x \
|
||||
&& v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|
||||
|| git describe --abbrev=4 HEAD 2>/dev/null` \
|
||||
&& v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \
|
||||
&& case $v in
|
||||
v[0-9]*) ;;
|
||||
*) (exit 1) ;;
|
||||
esac
|
||||
then
|
||||
# Is this a new git that lists number of commits since the last
|
||||
# tag or the previous older version that did not?
|
||||
# Newer: v6.10-77-g0f8faeb
|
||||
# Older: v6.10-g0f8faeb
|
||||
case $v in
|
||||
*-*-*) : git describe is okay three part flavor ;;
|
||||
*-*)
|
||||
: git describe is older two part flavor
|
||||
# Recreate the number of commits and rewrite such that the
|
||||
# result is the same as if we were using the newer version
|
||||
# of git describe.
|
||||
vtag=`echo "$v" | sed 's/-.*//'`
|
||||
commit_list=`git rev-list "$vtag"..HEAD 2>/dev/null` \
|
||||
|| { commit_list=failed;
|
||||
echo "$0: WARNING: git rev-list failed" 1>&2; }
|
||||
numcommits=`echo "$commit_list" | wc -l`
|
||||
v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
|
||||
test "$commit_list" = failed && v=UNKNOWN
|
||||
;;
|
||||
esac
|
||||
|
||||
# Change the first '-' to a '.', so version-comparing tools work properly.
|
||||
# Remove the "g" in git describe's output string, to save a byte.
|
||||
v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
|
||||
v_from_git=1
|
||||
else
|
||||
v=UNKNOWN
|
||||
fi
|
||||
|
||||
v=`echo "$v" |sed 's/^v//'`
|
||||
|
||||
# Test whether to append the "-dirty" suffix only if the version
|
||||
# string we're using came from git. I.e., skip the test if it's "UNKNOWN"
|
||||
# or if it came from .tarball-version.
|
||||
if test -n "$v_from_git"; then
|
||||
# Don't declare a version "dirty" merely because a time stamp has changed.
|
||||
git update-index --refresh > /dev/null 2>&1
|
||||
|
||||
dirty=`exec 2>/dev/null;git diff-index --name-only HEAD` || dirty=
|
||||
case "$dirty" in
|
||||
'') ;;
|
||||
*) # Append the suffix only if there isn't one already.
|
||||
case $v in
|
||||
*-dirty) ;;
|
||||
*) v="$v-dirty" ;;
|
||||
esac ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
|
||||
echo "$v" | tr -d "$nl"
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
191
build-aux/gitlog-to-changelog
Executable file
191
build-aux/gitlog-to-changelog
Executable file
@ -0,0 +1,191 @@
|
||||
eval '(exit $?0)' && eval 'exec perl -wS "$0" ${1+"$@"}'
|
||||
& eval 'exec perl -wS "$0" $argv:q'
|
||||
if 0;
|
||||
# Convert git log output to ChangeLog format.
|
||||
|
||||
my $VERSION = '2009-10-30 13:46'; # UTC
|
||||
# The definition above must lie within the first 8 lines in order
|
||||
# for the Emacs time-stamp write hook (at end) to update it.
|
||||
# If you change this file with Emacs, please let the write hook
|
||||
# do its job. Otherwise, update this string manually.
|
||||
|
||||
# Copyright (C) 2008-2010 Free Software Foundation, Inc.
|
||||
|
||||
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Written by Jim Meyering
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
use POSIX qw(strftime);
|
||||
|
||||
(my $ME = $0) =~ s|.*/||;
|
||||
|
||||
# use File::Coda; # http://meyering.net/code/Coda/
|
||||
END {
|
||||
defined fileno STDOUT or return;
|
||||
close STDOUT and return;
|
||||
warn "$ME: failed to close standard output: $!\n";
|
||||
$? ||= 1;
|
||||
}
|
||||
|
||||
sub usage ($)
|
||||
{
|
||||
my ($exit_code) = @_;
|
||||
my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR);
|
||||
if ($exit_code != 0)
|
||||
{
|
||||
print $STREAM "Try `$ME --help' for more information.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
print $STREAM <<EOF;
|
||||
Usage: $ME [OPTIONS] [ARGS]
|
||||
|
||||
Convert git log output to ChangeLog format. If present, any ARGS
|
||||
are passed to "git log". To avoid ARGS being parsed as options to
|
||||
$ME, they may be preceded by '--'.
|
||||
|
||||
OPTIONS:
|
||||
|
||||
--since=DATE convert only the logs since DATE;
|
||||
the default is to convert all log entries.
|
||||
--format=FMT set format string for commit subject and body;
|
||||
see 'man git-log' for the list of format metacharacters;
|
||||
the default is '%s%n%b%n'
|
||||
|
||||
--help display this help and exit
|
||||
--version output version information and exit
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
$ME --since=2008-01-01 > ChangeLog
|
||||
$ME -- -n 5 foo > last-5-commits-to-branch-foo
|
||||
|
||||
EOF
|
||||
}
|
||||
exit $exit_code;
|
||||
}
|
||||
|
||||
# If the string $S is a well-behaved file name, simply return it.
|
||||
# If it contains white space, quotes, etc., quote it, and return the new string.
|
||||
sub shell_quote($)
|
||||
{
|
||||
my ($s) = @_;
|
||||
if ($s =~ m![^\w+/.,-]!)
|
||||
{
|
||||
# Convert each single quote to '\''
|
||||
$s =~ s/\'/\'\\\'\'/g;
|
||||
# Then single quote the string.
|
||||
$s = "'$s'";
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
sub quoted_cmd(@)
|
||||
{
|
||||
return join (' ', map {shell_quote $_} @_);
|
||||
}
|
||||
|
||||
{
|
||||
my $since_date = '1970-01-01 UTC';
|
||||
my $format_string = '%s%n%b%n';
|
||||
GetOptions
|
||||
(
|
||||
help => sub { usage 0 },
|
||||
version => sub { print "$ME version $VERSION\n"; exit },
|
||||
'since=s' => \$since_date,
|
||||
'format=s' => \$format_string,
|
||||
) or usage 1;
|
||||
|
||||
my @cmd = (qw (git log --log-size), "--since=$since_date",
|
||||
'--pretty=format:%ct %an <%ae>%n%n'.$format_string, @ARGV);
|
||||
open PIPE, '-|', @cmd
|
||||
or die ("$ME: failed to run `". quoted_cmd (@cmd) ."': $!\n"
|
||||
. "(Is your Git too old? Version 1.5.1 or later is required.)\n");
|
||||
|
||||
my $prev_date_line = '';
|
||||
while (1)
|
||||
{
|
||||
defined (my $in = <PIPE>)
|
||||
or last;
|
||||
$in =~ /^log size (\d+)$/
|
||||
or die "$ME:$.: Invalid line (expected log size):\n$in";
|
||||
my $log_nbytes = $1;
|
||||
|
||||
my $log;
|
||||
my $n_read = read PIPE, $log, $log_nbytes;
|
||||
$n_read == $log_nbytes
|
||||
or die "$ME:$.: unexpected EOF\n";
|
||||
|
||||
my @line = split "\n", $log;
|
||||
my $author_line = shift @line;
|
||||
defined $author_line
|
||||
or die "$ME:$.: unexpected EOF\n";
|
||||
$author_line =~ /^(\d+) (.*>)$/
|
||||
or die "$ME:$.: Invalid line "
|
||||
. "(expected date/author/email):\n$author_line\n";
|
||||
|
||||
my $date_line = sprintf "%s $2\n", strftime ("%F", localtime ($1));
|
||||
# If this line would be the same as the previous date/name/email
|
||||
# line, then arrange not to print it.
|
||||
if ($date_line ne $prev_date_line)
|
||||
{
|
||||
$prev_date_line eq ''
|
||||
or print "\n";
|
||||
print $date_line;
|
||||
}
|
||||
$prev_date_line = $date_line;
|
||||
|
||||
# Omit "Signed-off-by..." lines.
|
||||
@line = grep !/^Signed-off-by: .*>$/, @line;
|
||||
|
||||
# If there were any lines
|
||||
if (@line == 0)
|
||||
{
|
||||
warn "$ME: warning: empty commit message:\n $date_line\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
# Remove leading and trailing blank lines.
|
||||
while ($line[0] =~ /^\s*$/) { shift @line; }
|
||||
while ($line[$#line] =~ /^\s*$/) { pop @line; }
|
||||
|
||||
# Prefix each non-empty line with a TAB.
|
||||
@line = map { length $_ ? "\t$_" : '' } @line;
|
||||
|
||||
print "\n", join ("\n", @line), "\n";
|
||||
}
|
||||
|
||||
defined ($in = <PIPE>)
|
||||
or last;
|
||||
$in ne "\n"
|
||||
and die "$ME:$.: unexpected line:\n$in";
|
||||
}
|
||||
|
||||
close PIPE
|
||||
or die "$ME: error closing pipe from " . quoted_cmd (@cmd) . "\n";
|
||||
# FIXME-someday: include $PROCESS_STATUS in the diagnostic
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# mode: perl
|
||||
# indent-tabs-mode: nil
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "my $VERSION = '"
|
||||
# time-stamp-format: "%:y-%02m-%02d %02H:%02M"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "'; # UTC"
|
||||
# End:
|
||||
75
build-aux/release.mk
Normal file
75
build-aux/release.mk
Normal file
@ -0,0 +1,75 @@
|
||||
# to build official release tarballs, handle tagging and publish.
|
||||
|
||||
# signing key
|
||||
gpgsignkey=956EEFB5
|
||||
|
||||
project=libqb
|
||||
|
||||
all: checks setup tag tarballs sha256 sign
|
||||
|
||||
checks:
|
||||
ifeq (,$(version))
|
||||
@echo ERROR: need to define version=
|
||||
@exit 1
|
||||
endif
|
||||
@if [ ! -d .git ]; then \
|
||||
echo This script needs to be executed from top level cluster git tree; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
setup: checks
|
||||
./autogen.sh
|
||||
./configure
|
||||
make maintainer-clean
|
||||
|
||||
tag: setup ./tag-$(version)
|
||||
|
||||
tag-$(version):
|
||||
ifeq (,$(release))
|
||||
@echo Building test release $(version), no tagging
|
||||
else
|
||||
git tag -a -m "v$(version) release" v$(version) HEAD
|
||||
@touch $@
|
||||
endif
|
||||
|
||||
tarballs: tag
|
||||
./autogen.sh
|
||||
./configure
|
||||
make distcheck
|
||||
|
||||
sha256: tarballs $(project)-$(version).sha256
|
||||
|
||||
$(project)-$(version).sha256:
|
||||
ifeq (,$(release))
|
||||
@echo Building test release $(version), no sha256
|
||||
else
|
||||
sha256sum $(project)-$(version)*tar* | sort -k2 > $@
|
||||
endif
|
||||
|
||||
sign: sha256 $(project)-$(version).sha256.asc
|
||||
|
||||
$(project)-$(version).sha256.asc: $(project)-$(version).sha256
|
||||
ifeq (,$(gpgsignkey))
|
||||
@echo No GPG signing key defined
|
||||
else
|
||||
ifeq (,$(release))
|
||||
@echo Building test release $(version), no sign
|
||||
else
|
||||
gpg --default-key $(gpgsignkey) \
|
||||
--detach-sign \
|
||||
--armor \
|
||||
$<
|
||||
endif
|
||||
endif
|
||||
|
||||
publish:
|
||||
ifeq (,$(release))
|
||||
@echo Building test release $(version), no publishing!
|
||||
else
|
||||
@echo CHANGEME git push --tags origin
|
||||
@echo CHANGEME scp $(project)-$(version).* \
|
||||
fedorahosted.org:$(project)
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -rf $(project)-* tag-*
|
||||
310
compile
Executable file
310
compile
Executable file
@ -0,0 +1,310 @@
|
||||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand '-c -o'.
|
||||
|
||||
scriptversion=2012-01-04.17; # UTC
|
||||
|
||||
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009, 2010, 2012 Free
|
||||
# Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# 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, 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# We need space, tab and new line, in precisely that order. Quoting is
|
||||
# there to prevent tools from complaining about whitespace usage.
|
||||
IFS=" "" $nl"
|
||||
|
||||
file_conv=
|
||||
|
||||
# func_file_conv build_file lazy
|
||||
# Convert a $build file to $host form and store it in $file
|
||||
# Currently only supports Windows hosts. If the determined conversion
|
||||
# type is listed in (the comma separated) LAZY, no conversion will
|
||||
# take place.
|
||||
func_file_conv ()
|
||||
{
|
||||
file=$1
|
||||
case $file in
|
||||
/ | /[!/]*) # absolute file, and not a UNC file
|
||||
if test -z "$file_conv"; then
|
||||
# lazily determine how to convert abs files
|
||||
case `uname -s` in
|
||||
MINGW*)
|
||||
file_conv=mingw
|
||||
;;
|
||||
CYGWIN*)
|
||||
file_conv=cygwin
|
||||
;;
|
||||
*)
|
||||
file_conv=wine
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case $file_conv/,$2, in
|
||||
*,$file_conv,*)
|
||||
;;
|
||||
mingw/*)
|
||||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
|
||||
;;
|
||||
cygwin/*)
|
||||
file=`cygpath -m "$file" || echo "$file"`
|
||||
;;
|
||||
wine/*)
|
||||
file=`winepath -w "$file" || echo "$file"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# func_cl_wrapper cl arg...
|
||||
# Adjust compile command to suit cl
|
||||
func_cl_wrapper ()
|
||||
{
|
||||
# Assume a capable shell
|
||||
lib_path=
|
||||
shared=:
|
||||
linker_opts=
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.[oO][bB][jJ])
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fo"$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fe"$file"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I*)
|
||||
func_file_conv "${1#-I}" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-l*)
|
||||
lib=${1#-l}
|
||||
found=no
|
||||
save_IFS=$IFS
|
||||
IFS=';'
|
||||
for dir in $lib_path $LIB
|
||||
do
|
||||
IFS=$save_IFS
|
||||
if $shared && test -f "$dir/$lib.dll.lib"; then
|
||||
found=yes
|
||||
set x "$@" "$dir/$lib.dll.lib"
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/$lib.lib"; then
|
||||
found=yes
|
||||
set x "$@" "$dir/$lib.lib"
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$save_IFS
|
||||
|
||||
test "$found" != yes && set x "$@" "$lib.lib"
|
||||
shift
|
||||
;;
|
||||
-L*)
|
||||
func_file_conv "${1#-L}"
|
||||
if test -z "$lib_path"; then
|
||||
lib_path=$file
|
||||
else
|
||||
lib_path="$lib_path;$file"
|
||||
fi
|
||||
linker_opts="$linker_opts -LIBPATH:$file"
|
||||
;;
|
||||
-static)
|
||||
shared=false
|
||||
;;
|
||||
-Wl,*)
|
||||
arg=${1#-Wl,}
|
||||
save_ifs="$IFS"; IFS=','
|
||||
for flag in $arg; do
|
||||
IFS="$save_ifs"
|
||||
linker_opts="$linker_opts $flag"
|
||||
done
|
||||
IFS="$save_ifs"
|
||||
;;
|
||||
-Xlinker)
|
||||
eat=1
|
||||
linker_opts="$linker_opts $2"
|
||||
;;
|
||||
-*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
|
||||
func_file_conv "$1"
|
||||
set x "$@" -Tp"$file"
|
||||
shift
|
||||
;;
|
||||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
|
||||
func_file_conv "$1" mingw
|
||||
set x "$@" "$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if test -n "$linker_opts"; then
|
||||
linker_opts="-link$linker_opts"
|
||||
fi
|
||||
exec "$@" $linker_opts
|
||||
exit 1
|
||||
}
|
||||
|
||||
eat=
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand '-c -o'.
|
||||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file 'INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
|
||||
func_cl_wrapper "$@" # Doesn't return...
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
# So we strip '-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no '-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# '.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
1522
config.guess
vendored
Executable file
1522
config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1766
config.sub
vendored
Executable file
1766
config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
543
configure.ac
Normal file
543
configure.ac
Normal file
@ -0,0 +1,543 @@
|
||||
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.61])
|
||||
|
||||
AC_INIT([libqb],
|
||||
m4_esyscmd([build-aux/git-version-gen .tarball-version]),
|
||||
[quarterback-devel@fedorahosted.org])
|
||||
AC_CONFIG_SRCDIR([lib/ringbuffer.c])
|
||||
AC_CONFIG_HEADERS([include/config.h include/qb/qbconfig.h])
|
||||
AM_INIT_AUTOMAKE([-Wno-portability dist-xz color-tests parallel-tests])
|
||||
dnl automake >= 1.11 offers --enable-silent-rules for suppressing the output from
|
||||
dnl normal compilation. When a failure occurs, it will then display the full
|
||||
dnl command line
|
||||
dnl Wrap in m4_ifdef to avoid breaking on older platforms
|
||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
||||
LT_PREREQ([2.2.6])
|
||||
LT_INIT
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CANONICAL_HOST
|
||||
AC_PROG_LIBTOOL
|
||||
AC_LANG([C])
|
||||
|
||||
dnl Fix default variables - "prefix" variable if not specified
|
||||
if test "$prefix" = "NONE"; then
|
||||
prefix="/usr"
|
||||
if test "$localstatedir" = "\${prefix}/var"; then
|
||||
localstatedir="/var"
|
||||
fi
|
||||
if test "$sysconfdir" = "\${prefix}/etc"; then
|
||||
sysconfdir="/etc"
|
||||
fi
|
||||
if test "$libdir" = "\${exec_prefix}/lib"; then
|
||||
if test -e /usr/lib64; then
|
||||
libdir="/usr/lib64"
|
||||
else
|
||||
libdir="/usr/lib"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$srcdir" = "."; then
|
||||
AC_MSG_NOTICE([building in place srcdir:$srcdir])
|
||||
AC_DEFINE([BUILDING_IN_PLACE], 1, [building in place])
|
||||
else
|
||||
AC_MSG_NOTICE([building out of tree srcdir:$srcdir])
|
||||
fi
|
||||
|
||||
# Checks for programs.
|
||||
|
||||
# check stolen from gnulib/m4/gnu-make.m4
|
||||
if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then
|
||||
AC_MSG_ERROR([you don't seem to have GNU make; it is required])
|
||||
fi
|
||||
|
||||
AC_PROG_CXX
|
||||
AC_PROG_AWK
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_CHECK_PROGS([PKGCONFIG], [pkg-config])
|
||||
AC_CHECK_PROGS([DOXYGEN], [doxygen])
|
||||
AM_CONDITIONAL(HAVE_DOXYGEN, test -n "${DOXYGEN}")
|
||||
AC_CHECK_PROGS([SPLINT], [splint])
|
||||
AM_CONDITIONAL(HAVE_SPLINT, test -n "${SPLINT}")
|
||||
|
||||
## local helper functions
|
||||
|
||||
# this function checks if CC support options passed as
|
||||
# args. Global CFLAGS are ignored during this test.
|
||||
cc_supports_flag() {
|
||||
local CPPFLAGS="$CPPFLAGS $@"
|
||||
AC_MSG_CHECKING([whether $CC supports "$@"])
|
||||
AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])],
|
||||
[RC=0; AC_MSG_RESULT([yes])],
|
||||
[RC=1; AC_MSG_RESULT([no])])
|
||||
return $RC
|
||||
}
|
||||
|
||||
## cleanup
|
||||
AC_MSG_NOTICE(Sanitizing prefix: ${prefix})
|
||||
case $prefix in
|
||||
NONE) prefix=/usr/local;;
|
||||
esac
|
||||
|
||||
AC_MSG_NOTICE(Sanitizing exec_prefix: ${exec_prefix})
|
||||
case $exec_prefix in
|
||||
NONE) exec_prefix=$prefix;;
|
||||
prefix) exec_prefix=$prefix;;
|
||||
esac
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB([rt], [mq_open])
|
||||
AC_CHECK_LIB([dl], [dlopen])
|
||||
AC_CHECK_LIB([pthread], [pthread_create])
|
||||
AC_CHECK_LIB([socket], [socket])
|
||||
|
||||
# look for testing harness "check"
|
||||
PKG_CHECK_MODULES([CHECK], [check >= 0.9.4],[with_check=yes],[with_check=no])
|
||||
AM_CONDITIONAL(HAVE_CHECK, test "${with_check}" = "yes")
|
||||
|
||||
# look for GLIB (used for testing integration)
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.0, have_glib=yes, have_glib=no)
|
||||
AM_CONDITIONAL(HAVE_GLIB, test x$have_glib = xyes)
|
||||
AC_SUBST(GLIB_CFLAGS)
|
||||
AC_SUBST(GLIB_LIBS)
|
||||
if test x"$have_glib" = xyes; then
|
||||
AC_DEFINE_UNQUOTED([HAVE_GLIB], [1], [We have glib])
|
||||
fi
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
|
||||
AC_CHECK_HEADERS([arpa/inet.h link.h fcntl.h inttypes.h limits.h netinet/in.h stdint.h \
|
||||
dlfcn.h time.h sys/time.h stdlib.h string.h strings.h sys/types.h sys/stat.h \
|
||||
sys/param.h sys/socket.h sys/time.h sys/poll.h sys/epoll.h sys/uio.h \
|
||||
sys/sockio.h sys/un.h sys/resource.h syslog.h errno.h unistd.h sys/mman.h \
|
||||
sys/sem.h sys/ipc.h sys/msg.h mqueue.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_TYPE_UID_T
|
||||
AC_C_INLINE
|
||||
AC_TYPE_INT32_T
|
||||
AC_TYPE_INT64_T
|
||||
AC_TYPE_INT8_T
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
AC_TYPE_UINT8_T
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_CHOWN
|
||||
AC_FUNC_FORK
|
||||
AC_FUNC_MMAP
|
||||
AC_CHECK_FUNCS([alarm clock_gettime ftruncate gettimeofday localtime localtime_r \
|
||||
memset munmap socket strchr strrchr strdup strerror strstr \
|
||||
poll epoll_create epoll_create1 random rand getrlimit sysconf \
|
||||
pthread_spin_lock pthread_setschedparam \
|
||||
sched_get_priority_max sched_setscheduler])
|
||||
|
||||
AC_CONFIG_LIBOBJ_DIR(lib)
|
||||
AC_REPLACE_FUNCS(strlcpy strlcat strchrnul)
|
||||
|
||||
## local defines
|
||||
PACKAGE_FEATURES=""
|
||||
|
||||
if test x$ac_cv_func_timerfd_create = xyes; then
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES timerfd"
|
||||
fi
|
||||
if test x$ac_cv_func_epoll_create = xyes; then
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES epoll"
|
||||
fi
|
||||
|
||||
nongcc_memory_barrier_needed=no
|
||||
arch_force_shmlba=no
|
||||
AC_MSG_CHECKING([for architecture in ${host_cpu}])
|
||||
case $host_cpu in
|
||||
sparc*)
|
||||
AC_MSG_RESULT([sparc])
|
||||
AC_DEFINE_UNQUOTED([QB_ARCH_SPARC], [1], [sparc])
|
||||
nongcc_memory_barrier_needed=yes
|
||||
arch_force_shmlba=yes
|
||||
;;
|
||||
alpha*)
|
||||
AC_MSG_RESULT([alpha])
|
||||
AC_DEFINE_UNQUOTED([QB_ARCH_ALPHA], [1], [alpha])
|
||||
nongcc_memory_barrier_needed=yes
|
||||
;;
|
||||
powerpc*)
|
||||
AC_MSG_RESULT([powerpc])
|
||||
AC_DEFINE_UNQUOTED([QB_ARCH_POWERPC], [1], [powerpc])
|
||||
ac_cv_link_attribute_section=no
|
||||
nongcc_memory_barrier_needed=yes
|
||||
arch_force_shmlba=yes
|
||||
;;
|
||||
ia64)
|
||||
AC_MSG_RESULT([ia64])
|
||||
AC_DEFINE_UNQUOTED([QB_ARCH_IA64], [1], [ia64])
|
||||
nongcc_memory_barrier_needed=yes
|
||||
;;
|
||||
arm*)
|
||||
AC_MSG_RESULT([ia64])
|
||||
AC_DEFINE_UNQUOTED([QB_ARCH_ARM], [1], [arm])
|
||||
arch_force_shmlba=yes
|
||||
;;
|
||||
mips*)
|
||||
AC_MSG_RESULT([ia64])
|
||||
AC_DEFINE_UNQUOTED([QB_ARCH_MIPS], [1], [mips])
|
||||
arch_force_shmlba=yes
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT([${host_cpu}])
|
||||
;;
|
||||
esac
|
||||
|
||||
if test $arch_force_shmlba = yes; then
|
||||
AC_DEFINE_UNQUOTED([QB_FORCE_SHM_ALIGN], [1],
|
||||
[shared and fixed mmap must align on 16k])
|
||||
fi
|
||||
|
||||
# OS detection
|
||||
# THIS SECTION MUST DIE!
|
||||
CP=cp
|
||||
LIB_RT=-lrt
|
||||
supports_sysv_mq="yes"
|
||||
supports_posix_mq="yes"
|
||||
AC_MSG_CHECKING([for os in ${host_os}])
|
||||
case "$host_os" in
|
||||
*linux*)
|
||||
AC_DEFINE_UNQUOTED([QB_LINUX], [1],
|
||||
[Compiling for Linux platform])
|
||||
AC_MSG_RESULT([Linux])
|
||||
;;
|
||||
darwin*)
|
||||
AC_DEFINE_UNQUOTED([QB_DARWIN], [1],
|
||||
[Compiling for Darwin platform])
|
||||
CP=rsync
|
||||
LIB_RT=
|
||||
supports_sysv_mq="no"
|
||||
supports_posix_mq="no"
|
||||
ac_cv_link_attribute_section=no
|
||||
dnl Attribute section appears to work here but fails later with:
|
||||
dnl cc1: error in backend: Global variable 'descriptor.4902' has an invalid section specifier '__verbose': mach-o section specifier requires a segment and section separated by a comma
|
||||
AC_DEFINE_UNQUOTED([MAP_ANONYMOUS], [MAP_ANON],
|
||||
[Shared memory define for Darwin platform])
|
||||
AC_DEFINE_UNQUOTED([PATH_MAX], [4096],
|
||||
[Number of chars in a path name including nul])
|
||||
AC_DEFINE_UNQUOTED([NAME_MAX], [255],
|
||||
[Number of chars in a file name])
|
||||
AC_DEFINE_UNQUOTED([DISABLE_POSIX_THREAD_PROCESS_SHARED], [1],
|
||||
[Disable _POSIX_THREAD_PROCESS_SHARED])
|
||||
AC_MSG_RESULT([Dawin])
|
||||
;;
|
||||
*bsd*)
|
||||
AC_DEFINE_UNQUOTED([QB_BSD], [1],
|
||||
[Compiling for BSD platform])
|
||||
AC_DEFINE_UNQUOTED([MAP_ANONYMOUS], [MAP_ANON],
|
||||
[Shared memory define for Darwin platform])
|
||||
case "$host_os" in
|
||||
*freebsd[[234567]]*)
|
||||
;;
|
||||
*freebsd*)
|
||||
AC_DEFINE_UNQUOTED([QB_FREEBSD_GE_8], [1],
|
||||
[Compiling for FreeBSD >= 8 platform])
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([BSD])
|
||||
;;
|
||||
*solaris*)
|
||||
AC_DEFINE_UNQUOTED([QB_SOLARIS], [1],
|
||||
[Compiling for Solaris platform])
|
||||
AC_DEFINE_UNQUOTED([TS_CLASS], [1],
|
||||
[Prevent being scheduled RR])
|
||||
AC_DEFINE_UNQUOTED([_SEM_SEMUN_UNDEFINED], [1],
|
||||
[The semun structure is undefined])
|
||||
CP=rsync
|
||||
AC_MSG_RESULT([Solaris])
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Unsupported OS? hmmmm])
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_MSG_CHECKING([whether GCC supports build-in atomic intrinsics])
|
||||
if test -z "$gcc_has_builtin_atomic_operations"; then
|
||||
gcc_has_builtin_atomic_operations=no
|
||||
if test x"$GCC" = xyes && test x$have_mingw != xyes; then
|
||||
AC_TRY_LINK([],
|
||||
[int i;
|
||||
__sync_synchronize ();
|
||||
__sync_bool_compare_and_swap (&i, 0, 1);
|
||||
__sync_fetch_and_add (&i, 1);
|
||||
],
|
||||
[gcc_has_builtin_atomic_operations=yes],
|
||||
[gcc_has_builtin_atomic_operations=no])
|
||||
fi
|
||||
fi
|
||||
AC_MSG_RESULT($gcc_has_builtin_atomic_operations)
|
||||
AM_CONDITIONAL(HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS,
|
||||
[test "x$gcc_has_builtin_atomic_operations" = xyes])
|
||||
|
||||
if test "x$gcc_has_builtin_atomic_operations" = xyes; then
|
||||
AC_DEFINE_UNQUOTED(HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS, 1,
|
||||
[have builtin atomic operations])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether atomics need memory barrier])
|
||||
if test -n "$ac_cv_atomic_need_memory_barrier"; then
|
||||
memory_barrier_needed=$ac_cv_atomic_need_memory_barrier
|
||||
else
|
||||
if test x$gcc_has_builtin_atomic_operations = xyes; then
|
||||
memory_barrier_needed=yes
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES gcc__sync"
|
||||
else
|
||||
memory_barrier_needed=$nongcc_memory_barrier_needed
|
||||
AC_MSG_WARN([-----------------------------])
|
||||
AC_MSG_WARN([You have gcc but not __sync_bool_compare_and_swap])
|
||||
AC_MSG_WARN([try CFLAGS="-march=<your arch> -mtune=native" ./configure])
|
||||
AC_MSG_WARN([-----------------------------])
|
||||
fi
|
||||
fi
|
||||
AC_MSG_RESULT($memory_barrier_needed)
|
||||
|
||||
if test x"$memory_barrier_needed" != xno; then
|
||||
AC_DEFINE_UNQUOTED(QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED, 1,
|
||||
[need atomic memory barrier])
|
||||
fi
|
||||
|
||||
LINT_FLAGS="-weak -unrecog +posixlib +ignoresigns -fcnuse \
|
||||
-badflag -D__gnuc_va_list=va_list -D__attribute\(x\)= \
|
||||
-warnposix +matchanyintegral"
|
||||
|
||||
# local options
|
||||
AC_ARG_ENABLE([ansi],
|
||||
[ --enable-ansi : force to build with ANSI standards. ],
|
||||
[ default="no" ])
|
||||
|
||||
AC_ARG_ENABLE([fatal-warnings],
|
||||
[ --enable-fatal-warnings : enable fatal warnings. ],
|
||||
[ default="no" ])
|
||||
|
||||
AC_ARG_ENABLE([debug],
|
||||
[ --enable-debug : enable debug build. ],
|
||||
[ default="no" ])
|
||||
|
||||
AC_ARG_ENABLE([coverage],
|
||||
[ --enable-coverage : coverage analysis of the codebase. ],
|
||||
[ default="no" ])
|
||||
|
||||
AC_ARG_ENABLE([slow-tests],
|
||||
[ --enable-slow-tests : build and run slow tests. ],
|
||||
[ default="no" ])
|
||||
|
||||
AC_ARG_WITH([socket-dir],
|
||||
[ --with-socket-dir=DIR : socket dir. ],
|
||||
[ SOCKETDIR="$withval" ],
|
||||
[ SOCKETDIR="$localstatedir/run" ])
|
||||
|
||||
AC_SUBST(CP)
|
||||
AC_SUBST(LIB_RT)
|
||||
# *FLAGS handling goes here
|
||||
|
||||
ENV_CFLAGS="$CFLAGS"
|
||||
ENV_CPPFLAGS="$CPPFLAGS"
|
||||
ENV_LDFLAGS="$LDFLAGS"
|
||||
|
||||
# debug build stuff
|
||||
if test "x${enable_debug}" = xyes; then
|
||||
AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code])
|
||||
OPT_CFLAGS="-O0"
|
||||
if test "x${GCC}" = xyes; then
|
||||
GDB_FLAGS="-ggdb3"
|
||||
else
|
||||
GDB_FLAGS="-g"
|
||||
fi
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES debug"
|
||||
fi
|
||||
|
||||
# extra warnings
|
||||
EXTRA_WARNINGS=""
|
||||
|
||||
WARNLIST="
|
||||
all
|
||||
shadow
|
||||
missing-prototypes
|
||||
missing-declarations
|
||||
strict-prototypes
|
||||
declaration-after-statement
|
||||
pointer-arith
|
||||
write-strings
|
||||
cast-align
|
||||
bad-function-cast
|
||||
missing-format-attribute
|
||||
format=2
|
||||
format-security
|
||||
no-format-nonliteral
|
||||
no-long-long
|
||||
unsigned-char
|
||||
gnu89-inline
|
||||
no-strict-aliasing
|
||||
"
|
||||
|
||||
for j in $WARNLIST; do
|
||||
if cc_supports_flag -W$j; then
|
||||
EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j";
|
||||
fi
|
||||
done
|
||||
|
||||
# --- coverage ---
|
||||
if test "x${enable_coverage}" = xyes && \
|
||||
cc_supports_flag -ftest-coverage && \
|
||||
cc_supports_flag -fprofile-arcs ; then
|
||||
AC_MSG_NOTICE([Enabling Coverage (enable -O0 by default)])
|
||||
OPT_CFLAGS="-O0"
|
||||
COVERAGE_CFLAGS="-ftest-coverage -fprofile-arcs"
|
||||
COVERAGE_LDFLAGS="-ftest-coverage -fprofile-arcs"
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES coverage"
|
||||
else
|
||||
COVERAGE_CFLAGS=""
|
||||
COVERAGE_LDFLAGS=""
|
||||
fi
|
||||
|
||||
if test "x${enable_slow_tests}" = xyes ; then
|
||||
AC_DEFINE([HAVE_SLOW_TESTS], 1,[have slow tests])
|
||||
AC_MSG_NOTICE([Enabling Slow tests])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_SLOW_TESTS, [test "x${enable_slow_tests}" = xyes])
|
||||
|
||||
if test -n "$ac_cv_supports_sysv_mq"; then
|
||||
supports_sysv_mq=$ac_cv_supports_sysv_mq
|
||||
fi
|
||||
if test "x${supports_sysv_mq}" = xyes ; then
|
||||
AC_DEFINE([HAVE_SYSV_MQ], [1],
|
||||
[have sysv message queues])
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES sysv_mq"
|
||||
AC_MSG_NOTICE([Enabling SYSV Message Queues])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_SYSV_MQ, [test "x${supports_sysv_mq}" = xyes])
|
||||
|
||||
if test -n "$ac_cv_supports_posix_mq"; then
|
||||
supports_posix_mq=$ac_cv_supports_posix_mq
|
||||
fi
|
||||
if test "x${supports_posix_mq}" = xyes ; then
|
||||
AC_DEFINE([HAVE_POSIX_MQ], [1],
|
||||
[have posix message queues])
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES posix_mq"
|
||||
AC_MSG_NOTICE([Enabling POSIX Message Queues])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_POSIX_MQ, [test "x${supports_posix_mq}" = xyes])
|
||||
|
||||
# --- callsite sections ---
|
||||
if test "x${GCC}" = xyes; then
|
||||
AC_MSG_CHECKING([whether GCC supports __attribute__((section())])
|
||||
if test "x${ac_cv_link_attribute_section}" = x ; then
|
||||
AC_TRY_LINK([],
|
||||
[static int my_var __attribute__((section("__verbose"))) = 5;
|
||||
if (my_var == 5) return 0;
|
||||
else return -1;
|
||||
],
|
||||
[gcc_has_attribute_section=yes],
|
||||
[gcc_has_attribute_section=no])
|
||||
else
|
||||
gcc_has_attribute_section=${ac_cv_link_attribute_section}
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT($gcc_has_attribute_section)
|
||||
if test $gcc_has_attribute_section = yes; then
|
||||
AC_DEFINE([QB_HAVE_ATTRIBUTE_SECTION], 1,
|
||||
[Enabling code using __attribute__((section))])
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- ansi ---
|
||||
if test "x${enable_ansi}" = xyes && \
|
||||
cc_supports_flag -std=iso9899:199409 ; then
|
||||
AC_MSG_NOTICE([Enabling ANSI Compatibility])
|
||||
ANSI_CPPFLAGS="-ansi -D_GNU_SOURCE -DANSI_ONLY"
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES ansi"
|
||||
else
|
||||
ANSI_CPPFLAGS=""
|
||||
fi
|
||||
|
||||
# --- fatal warnings ---
|
||||
if test "x${enable_fatal_warnings}" = xyes && \
|
||||
cc_supports_flag -Werror ; then
|
||||
AC_MSG_NOTICE([Enabling Fatal Warnings (-Werror)])
|
||||
WERROR_CFLAGS="-Werror"
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES fatal-warnings"
|
||||
else
|
||||
WERROR_CFLAGS=""
|
||||
fi
|
||||
|
||||
# final build of *FLAGS
|
||||
CFLAGS="$ENV_CFLAGS $OPT_CFLAGS $GDB_FLAGS \
|
||||
$COVERAGE_CFLAGS $EXTRA_WARNINGS $WERROR_CFLAGS"
|
||||
CPPFLAGS="$ENV_CPPFLAGS $ANSI_CPPFLAGS"
|
||||
LDFLAGS="$ENV_LDFLAGS $COVERAGE_LDFLAGS"
|
||||
|
||||
if test -f /usr/share/dict/words ; then
|
||||
HAVE_DICT_WORDS=yes
|
||||
AC_DEFINE([HAVE_DICT_WORDS], 1, "Have /usr/share/dict/words")
|
||||
fi
|
||||
AM_CONDITIONAL([HAVE_DICT_WORDS], [test "x$HAVE_DICT_WORDS" = xyes])
|
||||
|
||||
# substitute what we need:
|
||||
AC_SUBST([SOCKETDIR])
|
||||
AC_SUBST([LINT_FLAGS])
|
||||
|
||||
AC_DEFINE_UNQUOTED([SOCKETDIR], "$(eval echo ${SOCKETDIR})", [Socket directory])
|
||||
AC_DEFINE_UNQUOTED([LOCALSTATEDIR], "$(eval echo ${localstatedir})", [localstate directory])
|
||||
AC_DEFINE_UNQUOTED([PACKAGE_FEATURES], "${PACKAGE_FEATURES}", [quarterback built-in features])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
include/Makefile
|
||||
include/qb/Makefile
|
||||
lib/Makefile
|
||||
lib/libqb.pc
|
||||
tests/Makefile
|
||||
examples/Makefile
|
||||
docs/Makefile
|
||||
docs/man.dox
|
||||
docs/html.dox])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_RESULT([])
|
||||
AC_MSG_RESULT([$PACKAGE configuration:])
|
||||
AC_MSG_RESULT([ Version = ${VERSION}])
|
||||
AC_MSG_RESULT([ Prefix = ${prefix}])
|
||||
AC_MSG_RESULT([ Executables = ${sbindir}])
|
||||
AC_MSG_RESULT([ Man pages = ${mandir}])
|
||||
AC_MSG_RESULT([ Doc dir = ${docdir}])
|
||||
AC_MSG_RESULT([ Libraries = ${libdir}])
|
||||
AC_MSG_RESULT([ Header files = ${includedir}])
|
||||
AC_MSG_RESULT([ Arch-independent files = ${datadir}])
|
||||
AC_MSG_RESULT([ State information = ${localstatedir}])
|
||||
AC_MSG_RESULT([ System configuration = ${sysconfdir}])
|
||||
AC_MSG_RESULT([ SOCKETDIR = ${SOCKETDIR}])
|
||||
AC_MSG_RESULT([ Features =${PACKAGE_FEATURES}])
|
||||
AC_MSG_RESULT([])
|
||||
AC_MSG_RESULT([$PACKAGE build info:])
|
||||
AC_MSG_RESULT([ Optimization = ${OPT_CFLAGS}])
|
||||
AC_MSG_RESULT([ Debug options = ${GDB_CFLAGS}])
|
||||
AC_MSG_RESULT([ Extra compiler warnings = ${EXTRA_WARNING}])
|
||||
AC_MSG_RESULT([ Env. defined CFLAG = ${ENV_CFLAGS}])
|
||||
AC_MSG_RESULT([ Env. defined CPPFLAGS = ${ENV_CPPFLAGS}])
|
||||
AC_MSG_RESULT([ Env. defined LDFLAGS = ${ENV_LDFLAGS}])
|
||||
AC_MSG_RESULT([ ANSI defined CPPFLAGS = ${ANSI_CPPFLAGS}])
|
||||
AC_MSG_RESULT([ Coverage CFLAGS = ${COVERAGE_CFLAGS}])
|
||||
AC_MSG_RESULT([ Coverage LDFLAGS = ${COVERAGE_LDFLAGS}])
|
||||
AC_MSG_RESULT([ Fatal War. CFLAGS = ${WERROR_CFLAGS}])
|
||||
AC_MSG_RESULT([ Final CFLAGS = ${CFLAGS}])
|
||||
AC_MSG_RESULT([ Final CPPFLAGS = ${CPPFLAGS}])
|
||||
AC_MSG_RESULT([ Final LDFLAGS = ${LDFLAGS}])
|
||||
688
depcomp
Executable file
688
depcomp
Executable file
@ -0,0 +1,688 @@
|
||||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2011-12-04.11; # UTC
|
||||
|
||||
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
|
||||
# 2011 Free Software Foundation, Inc.
|
||||
|
||||
# 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, 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||
as side-effects.
|
||||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by `PROGRAMS ARGS'.
|
||||
object Object file output by `PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputting dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||
depfile=${depfile-`echo "$object" |
|
||||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
cygpath_u="cygpath -u -f -"
|
||||
if test "$depmode" = msvcmsys; then
|
||||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
if test "$depmode" = msvc7msys; then
|
||||
# This is just like msvc7 but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvc7
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
|
||||
## the command line argument order; so add the flags where they
|
||||
## appear in depend2.am. Note that the slowdown incurred here
|
||||
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
|
||||
*) set fnord "$@" "$arg" ;;
|
||||
esac
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
done
|
||||
"$@"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say).
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
|
||||
## The second -e expression handles DOS-style file names with drive letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the `deleted header file' problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" |
|
||||
## Some versions of gcc put a space before the `:'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well. hp depmode also adds that space, but also prefixes the VPATH
|
||||
## to the object. Take care to not repeat it in the output.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like `#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
|
||||
tr '
|
||||
' ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts `$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||
test "x$dir" = "x$object" && dir=
|
||||
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$base.u
|
||||
tmpdepfile3=$dir.libs/$base.u
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$dir$base.u
|
||||
tmpdepfile3=$dir$base.u
|
||||
"$@" -M
|
||||
fi
|
||||
stat=$?
|
||||
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form `foo.o: dependent.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||
# That's a tab and a space in the [].
|
||||
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
icc)
|
||||
# Intel's C compiler understands `-MD -MF file'. However on
|
||||
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
|
||||
# ICC 7.0 will fill foo.d with something like
|
||||
# foo.o: sub/foo.c
|
||||
# foo.o: sub/foo.h
|
||||
# which is wrong. We want:
|
||||
# sub/foo.o: sub/foo.c
|
||||
# sub/foo.o: sub/foo.h
|
||||
# sub/foo.c:
|
||||
# sub/foo.h:
|
||||
# ICC 7.1 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using \ :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
|
||||
sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp2)
|
||||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
|
||||
# compilers, which have integrated preprocessors. The correct option
|
||||
# to use with these is +Maked; it writes dependencies to a file named
|
||||
# 'foo.d', which lands next to the object file, wherever that
|
||||
# happens to be.
|
||||
# Much of this is similar to the tru64 case; see comments there.
|
||||
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||
test "x$dir" = "x$object" && dir=
|
||||
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir.libs/$base.d
|
||||
"$@" -Wc,+Maked
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
"$@" +Maked
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add `dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile" "$tmpdepfile2"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in `foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||
test "x$dir" = "x$object" && dir=
|
||||
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# With Tru64 cc, shared objects can also be used to make a
|
||||
# static library. This mechanism is used in libtool 1.4 series to
|
||||
# handle both shared and static libraries in a single compilation.
|
||||
# With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
|
||||
#
|
||||
# With libtool 1.5 this exception was removed, and libtool now
|
||||
# generates 2 separate objects for the 2 libraries. These two
|
||||
# compilations output dependencies in $dir.libs/$base.o.d and
|
||||
# in $dir$base.o.d. We have to check for both files, because
|
||||
# one of the two compilations can be disabled. We should prefer
|
||||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||
# the former would cause a distcleancheck panic.
|
||||
tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
|
||||
tmpdepfile2=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
|
||||
tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.o.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
tmpdepfile4=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||
# That's a tab and a space in the [].
|
||||
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7)
|
||||
if test "$libtool" = yes; then
|
||||
showIncludes=-Wc,-showIncludes
|
||||
else
|
||||
showIncludes=-showIncludes
|
||||
fi
|
||||
"$@" $showIncludes > "$tmpdepfile"
|
||||
stat=$?
|
||||
grep -v '^Note: including file: ' "$tmpdepfile"
|
||||
if test "$stat" = 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The first sed program below extracts the file names and escapes
|
||||
# backslashes for cygpath. The second sed program outputs the file
|
||||
# name when reading, but also accumulates all include files in the
|
||||
# hold buffer in order to output them again at the end. This only
|
||||
# works with sed implementations that can handle large buffers.
|
||||
sed < "$tmpdepfile" -n '
|
||||
/^Note: including file: *\(.*\)/ {
|
||||
s//\1/
|
||||
s/\\/\\\\/g
|
||||
p
|
||||
}' | $cygpath_u | sort -u | sed -n '
|
||||
s/ /\\ /g
|
||||
s/\(.*\)/ \1 \\/p
|
||||
s/.\(.*\) \\/\1:/
|
||||
H
|
||||
$ {
|
||||
s/.*/ /
|
||||
G
|
||||
p
|
||||
}' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7msys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout, regardless of -o.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove `-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for `:'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
"$@" || exit $?
|
||||
# Remove any Libtool call
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
# X makedepend
|
||||
shift
|
||||
cleared=no eat=no
|
||||
for arg
|
||||
do
|
||||
case $cleared in
|
||||
no)
|
||||
set ""; shift
|
||||
cleared=yes ;;
|
||||
esac
|
||||
if test $eat = yes; then
|
||||
eat=no
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
# Strip any option that makedepend may not understand. Remove
|
||||
# the object too, otherwise makedepend will parse it as a source file.
|
||||
-arch)
|
||||
eat=yes ;;
|
||||
-*|$object)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
esac
|
||||
done
|
||||
obj_suffix=`echo "$object" | sed 's/^.*\././'`
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
# makedepend may prepend the VPATH from the source file name to the object.
|
||||
# No need to regex-escape $object, excess matching of '.' is harmless.
|
||||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
|
||||
sed '1,2d' "$tmpdepfile" | tr ' ' '
|
||||
' | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove `-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
"$@" -E |
|
||||
sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
|
||||
sed '$ s: \\$::' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E 2>/dev/null |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
|
||||
echo " " >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvcmsys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
48
docs/Makefile.am
Normal file
48
docs/Makefile.am
Normal file
@ -0,0 +1,48 @@
|
||||
# Copyright (C) 2010 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Angus Salkeld <asalkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
EXTRA_DIST = man.dox html.dox
|
||||
noinst_HEADERS = mainpage.h
|
||||
|
||||
if HAVE_DOXYGEN
|
||||
inc_dir = $(top_srcdir)/include/qb
|
||||
dependant_headers = $(wildcard $(inc_dir)/qb*.h)
|
||||
dist_man_MANS = man3/qbipcc.h.3 man3/qbipcs.h.3 man3/qbatomic.h.3 \
|
||||
man3/qbhdb.h.3 man3/qbipc_common.h.3 man3/qblist.h.3 \
|
||||
man3/qbloop.h.3 man3/qbutil.h.3 man3/qbarray.h.3 \
|
||||
man3/qblog.h.3 man3/qbmap.h.3
|
||||
|
||||
|
||||
$(dist_man_MANS): man.dox $(dependant_headers)
|
||||
@mkdir -p man3
|
||||
@doxygen man.dox
|
||||
|
||||
doxygen: html.dox
|
||||
@mkdir -p html
|
||||
@doxygen html.dox
|
||||
|
||||
else
|
||||
doxygen:
|
||||
@echo WARNING: no doxygen to build man pages!
|
||||
endif
|
||||
|
||||
clean-generic:
|
||||
rm -rf html man3
|
||||
|
||||
569
docs/Makefile.in
Normal file
569
docs/Makefile.in
Normal file
@ -0,0 +1,569 @@
|
||||
# Makefile.in generated by automake 1.11.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# Copyright (C) 2010 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Angus Salkeld <asalkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = docs
|
||||
DIST_COMMON = $(dist_man_MANS) $(noinst_HEADERS) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in $(srcdir)/html.dox.in \
|
||||
$(srcdir)/man.dox.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/include/config.h \
|
||||
$(top_builddir)/include/qb/qbconfig.h
|
||||
CONFIG_CLEAN_FILES = man.dox html.dox
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
man3dir = $(mandir)/man3
|
||||
am__installdirs = "$(DESTDIR)$(man3dir)"
|
||||
NROFF = nroff
|
||||
MANS = $(dist_man_MANS)
|
||||
HEADERS = $(noinst_HEADERS)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CHECK_CFLAGS = @CHECK_CFLAGS@
|
||||
CHECK_LIBS = @CHECK_LIBS@
|
||||
CP = @CP@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DOXYGEN = @DOXYGEN@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GLIB_CFLAGS = @GLIB_CFLAGS@
|
||||
GLIB_LIBS = @GLIB_LIBS@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIB_RT = @LIB_RT@
|
||||
LINT_FLAGS = @LINT_FLAGS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKGCONFIG = @PKGCONFIG@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
SOCKETDIR = @SOCKETDIR@
|
||||
SPLINT = @SPLINT@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
EXTRA_DIST = man.dox html.dox
|
||||
noinst_HEADERS = mainpage.h
|
||||
@HAVE_DOXYGEN_TRUE@inc_dir = $(top_srcdir)/include/qb
|
||||
@HAVE_DOXYGEN_TRUE@dependant_headers = $(wildcard $(inc_dir)/qb*.h)
|
||||
@HAVE_DOXYGEN_TRUE@dist_man_MANS = man3/qbipcc.h.3 man3/qbipcs.h.3 man3/qbatomic.h.3 \
|
||||
@HAVE_DOXYGEN_TRUE@ man3/qbhdb.h.3 man3/qbipc_common.h.3 man3/qblist.h.3 \
|
||||
@HAVE_DOXYGEN_TRUE@ man3/qbloop.h.3 man3/qbutil.h.3 man3/qbarray.h.3 \
|
||||
@HAVE_DOXYGEN_TRUE@ man3/qblog.h.3 man3/qbmap.h.3
|
||||
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu docs/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu docs/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
man.dox: $(top_builddir)/config.status $(srcdir)/man.dox.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
html.dox: $(top_builddir)/config.status $(srcdir)/html.dox.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
install-man3: $(dist_man_MANS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(man3dir)" || $(MKDIR_P) "$(DESTDIR)$(man3dir)"
|
||||
@list=''; test -n "$(man3dir)" || exit 0; \
|
||||
{ for i in $$list; do echo "$$i"; done; \
|
||||
l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \
|
||||
sed -n '/\.3[a-z]*$$/p'; \
|
||||
} | while read p; do \
|
||||
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; echo "$$p"; \
|
||||
done | \
|
||||
sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
|
||||
sed 'N;N;s,\n, ,g' | { \
|
||||
list=; while read file base inst; do \
|
||||
if test "$$base" = "$$inst"; then list="$$list $$file"; else \
|
||||
echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
|
||||
$(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \
|
||||
fi; \
|
||||
done; \
|
||||
for i in $$list; do echo "$$i"; done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
test -z "$$files" || { \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \
|
||||
done; }
|
||||
|
||||
uninstall-man3:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list=''; test -n "$(man3dir)" || exit 0; \
|
||||
files=`{ for i in $$list; do echo "$$i"; done; \
|
||||
l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \
|
||||
sed -n '/\.3[a-z]*$$/p'; \
|
||||
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
|
||||
dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir)
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@list='$(MANS)'; if test -n "$$list"; then \
|
||||
list=`for p in $$list; do \
|
||||
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
|
||||
if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
|
||||
if test -n "$$list" && \
|
||||
grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
|
||||
echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \
|
||||
grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \
|
||||
echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \
|
||||
echo " typically \`make maintainer-clean' will remove them" >&2; \
|
||||
exit 1; \
|
||||
else :; fi; \
|
||||
else :; fi
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(MANS) $(HEADERS)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(man3dir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-man
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man: install-man3
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-man
|
||||
|
||||
uninstall-man: uninstall-man3
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool ctags distclean distclean-generic \
|
||||
distclean-libtool distclean-tags distdir dvi dvi-am html \
|
||||
html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-man install-man3 install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-generic \
|
||||
mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
|
||||
uninstall-am uninstall-man uninstall-man3
|
||||
|
||||
|
||||
@HAVE_DOXYGEN_TRUE@$(dist_man_MANS): man.dox $(dependant_headers)
|
||||
@HAVE_DOXYGEN_TRUE@ @mkdir -p man3
|
||||
@HAVE_DOXYGEN_TRUE@ @doxygen man.dox
|
||||
|
||||
@HAVE_DOXYGEN_TRUE@doxygen: html.dox
|
||||
@HAVE_DOXYGEN_TRUE@ @mkdir -p html
|
||||
@HAVE_DOXYGEN_TRUE@ @doxygen html.dox
|
||||
|
||||
@HAVE_DOXYGEN_FALSE@doxygen:
|
||||
@HAVE_DOXYGEN_FALSE@ @echo WARNING: no doxygen to build man pages!
|
||||
|
||||
clean-generic:
|
||||
rm -rf html man3
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
214
docs/html.dox
Normal file
214
docs/html.dox
Normal file
@ -0,0 +1,214 @@
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = libqb
|
||||
PROJECT_NUMBER = 0.11.1
|
||||
OUTPUT_DIRECTORY = .
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = YES
|
||||
ALWAYS_DETAILED_SEC = YES
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
EXTENSION_MAPPING =
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = YES
|
||||
SUBGROUPING = NO
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
SYMBOL_CACHE_SIZE = 0
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
EXTRACT_LOCAL_METHODS = YES
|
||||
EXTRACT_ANON_NSPACES = YES
|
||||
HIDE_UNDOC_MEMBERS = YES
|
||||
HIDE_UNDOC_CLASSES = YES
|
||||
HIDE_FRIEND_COMPOUNDS = YES
|
||||
HIDE_IN_BODY_DOCS = YES
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT =
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = ./../include/qb/ ./../docs/
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.h
|
||||
RECURSIVE = NO
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH = ./../examples
|
||||
EXAMPLE_PATTERNS = *.c
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = YES
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE =
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
USE_INLINE_TREES = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
FORMULA_FONTSIZE = 10
|
||||
SEARCHENGINE = YES
|
||||
GENERATE_LATEX = YES
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = NO
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_SOURCE_CODE = NO
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = .
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_RTF = NO
|
||||
GENERATE_XML = NO
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
GENERATE_PERLMOD = NO
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH = ./../include
|
||||
INCLUDE_FILE_PATTERNS = *.h
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = NO
|
||||
PERL_PATH =
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
DOT_FONTNAME = FreeSans
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = YES
|
||||
TEMPLATE_RELATIONS = YES
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
214
docs/html.dox.in
Normal file
214
docs/html.dox.in
Normal file
@ -0,0 +1,214 @@
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = libqb
|
||||
PROJECT_NUMBER = @VERSION@
|
||||
OUTPUT_DIRECTORY = .
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = YES
|
||||
ALWAYS_DETAILED_SEC = YES
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
EXTENSION_MAPPING =
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = YES
|
||||
SUBGROUPING = NO
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
SYMBOL_CACHE_SIZE = 0
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
EXTRACT_LOCAL_METHODS = YES
|
||||
EXTRACT_ANON_NSPACES = YES
|
||||
HIDE_UNDOC_MEMBERS = YES
|
||||
HIDE_UNDOC_CLASSES = YES
|
||||
HIDE_FRIEND_COMPOUNDS = YES
|
||||
HIDE_IN_BODY_DOCS = YES
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT =
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = @srcdir@/../include/qb/ @srcdir@/../docs/
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.h
|
||||
RECURSIVE = NO
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH = @srcdir@/../examples
|
||||
EXAMPLE_PATTERNS = *.c
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = YES
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE =
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
USE_INLINE_TREES = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
FORMULA_FONTSIZE = 10
|
||||
SEARCHENGINE = YES
|
||||
GENERATE_LATEX = YES
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = NO
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_SOURCE_CODE = NO
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = .
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_RTF = NO
|
||||
GENERATE_XML = NO
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
GENERATE_PERLMOD = NO
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH = @srcdir@/../include
|
||||
INCLUDE_FILE_PATTERNS = *.h
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = NO
|
||||
PERL_PATH =
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
DOT_FONTNAME = FreeSans
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = YES
|
||||
TEMPLATE_RELATIONS = YES
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
117
docs/mainpage.h
Normal file
117
docs/mainpage.h
Normal file
@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @mainpage
|
||||
*
|
||||
* @section overview Overview
|
||||
*
|
||||
* libqb is a thread-safe library with the primary purpose of providing high performance client server reusable features.
|
||||
*
|
||||
* It provides high performance ipc, and poll.
|
||||
*
|
||||
* We don't intend be an all encompassing library, but instead provide very specially focused APIs that are highly
|
||||
*
|
||||
* tuned for maximum performance for client/server applications.
|
||||
*
|
||||
* See the following pages for more info:
|
||||
* - @subpage qb_list_overview
|
||||
* - @subpage qb_atomic_overview
|
||||
* - @subpage qb_array_overview
|
||||
* - @subpage qb_map_overview
|
||||
* - @subpage qb_hdb_overview
|
||||
* - @subpage qb_rb_overview
|
||||
* - @subpage qb_loop_overview
|
||||
* - @subpage qb_log_overview
|
||||
* - @subpage qb_ipc_overview
|
||||
* - @subpage qb_util_overview
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page qb_rb_overview Ringbuffer
|
||||
* @copydoc qbrb.h
|
||||
* @see qbrb.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page qb_list_overview List
|
||||
* @copydoc qblist.h
|
||||
* @see qblist.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page qb_array_overview Array
|
||||
* @copydoc qbarray.h
|
||||
* @see qbarray.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page qb_map_overview Map
|
||||
* @copydoc qbmap.h
|
||||
* @see qbmap.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page qb_hdb_overview Handle Database
|
||||
* @copydoc qbhdb.h
|
||||
* @see qbhdb.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page qb_loop_overview Main Loop
|
||||
* @copydoc qbloop.h
|
||||
* @see qbloop.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page qb_log_overview Logging
|
||||
* @copydoc qblog.h
|
||||
* @see qblog.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page qb_ipc_overview IPC Overview
|
||||
*
|
||||
* @par Overview
|
||||
* libqb provides a generically reusable very high performance shared memory IPC sytem for client
|
||||
* and service applications. It supports many features including:
|
||||
* - Multiple transport implementations
|
||||
* -# Shared memory implementation for very high performance.
|
||||
* -# Posix Message queues
|
||||
* -# SysV Message queues
|
||||
* -# Unix sockets
|
||||
* - A synchronous request/response channel and asynchronous response channel per ipc connection.
|
||||
* - User defined private data per IPC connection.
|
||||
* - Ability to call a function per service on ipc connection and disconnection.
|
||||
* - Authenticated IPC connection with ability for developer to define which UIDs and GIDs are valid at connection time.
|
||||
* - Fully abstracted poll system so that any poll library may be used.
|
||||
* - User defined selector for determining the proper function to call per service and id.
|
||||
*
|
||||
* @par Security
|
||||
* The ipc system uses default operating system security mechanics to ensure ipc
|
||||
* connections are validated. A callback used with qb_ipcs_create() is called
|
||||
* for every new ipc connection with the parameters of UID and GID. The callback
|
||||
* then determines if the UID and GID are authenticated for communication.
|
||||
*
|
||||
* @par Performance
|
||||
* For performance QB_IPC_SHM (shared memory) is recogmended. It is tuned for
|
||||
* very high performance.
|
||||
*
|
||||
* @par Client API
|
||||
* @copydoc qbipcc.h
|
||||
* @see qbipcc.h
|
||||
*
|
||||
* @par Server API
|
||||
* @copydoc qbipcs.h
|
||||
* @see qbipcs.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page qb_atomic_overview Atomic operations
|
||||
* @copydoc qbatomic.h
|
||||
* @see qbatomic.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page qb_util_overview Common Utilities
|
||||
* @copydoc qbutil.h
|
||||
* @see qbutil.h
|
||||
*/
|
||||
162
docs/man.dox
Normal file
162
docs/man.dox
Normal file
@ -0,0 +1,162 @@
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = libqb
|
||||
PROJECT_NUMBER = 0.11.1
|
||||
OUTPUT_DIRECTORY = .
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = YES
|
||||
ALWAYS_DETAILED_SEC = YES
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
EXTENSION_MAPPING =
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = YES
|
||||
SUBGROUPING = NO
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
SYMBOL_CACHE_SIZE = 0
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
EXTRACT_LOCAL_METHODS = YES
|
||||
EXTRACT_ANON_NSPACES = YES
|
||||
HIDE_UNDOC_MEMBERS = YES
|
||||
HIDE_UNDOC_CLASSES = YES
|
||||
HIDE_FRIEND_COMPOUNDS = YES
|
||||
HIDE_IN_BODY_DOCS = YES
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = NO
|
||||
GENERATE_TESTLIST = NO
|
||||
GENERATE_BUGLIST = NO
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT =
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = ./../include/qb/ ./../docs/
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.h
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = YES
|
||||
MAN_OUTPUT = .
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = YES
|
||||
GENERATE_HTML = NO
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_RTF = NO
|
||||
GENERATE_XML = NO
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
GENERATE_PERLMOD = NO
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH = ../include
|
||||
INCLUDE_FILE_PATTERNS = *.h
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = NO
|
||||
PERL_PATH =
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
DOT_FONTNAME = FreeSans
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = NO
|
||||
COLLABORATION_GRAPH = NO
|
||||
GROUP_GRAPHS = NO
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = NO
|
||||
INCLUDED_BY_GRAPH = NO
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = NO
|
||||
DIRECTORY_GRAPH = NO
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
162
docs/man.dox.in
Normal file
162
docs/man.dox.in
Normal file
@ -0,0 +1,162 @@
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = libqb
|
||||
PROJECT_NUMBER = @VERSION@
|
||||
OUTPUT_DIRECTORY = .
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = YES
|
||||
ALWAYS_DETAILED_SEC = YES
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
EXTENSION_MAPPING =
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = YES
|
||||
SUBGROUPING = NO
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
SYMBOL_CACHE_SIZE = 0
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
EXTRACT_LOCAL_METHODS = YES
|
||||
EXTRACT_ANON_NSPACES = YES
|
||||
HIDE_UNDOC_MEMBERS = YES
|
||||
HIDE_UNDOC_CLASSES = YES
|
||||
HIDE_FRIEND_COMPOUNDS = YES
|
||||
HIDE_IN_BODY_DOCS = YES
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = NO
|
||||
GENERATE_TESTLIST = NO
|
||||
GENERATE_BUGLIST = NO
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT =
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = @srcdir@/../include/qb/ @srcdir@/../docs/
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.h
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = YES
|
||||
MAN_OUTPUT = .
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = YES
|
||||
GENERATE_HTML = NO
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_RTF = NO
|
||||
GENERATE_XML = NO
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
GENERATE_PERLMOD = NO
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH = ../include
|
||||
INCLUDE_FILE_PATTERNS = *.h
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = NO
|
||||
PERL_PATH =
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
DOT_FONTNAME = FreeSans
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = NO
|
||||
COLLABORATION_GRAPH = NO
|
||||
GROUP_GRAPHS = NO
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = NO
|
||||
INCLUDED_BY_GRAPH = NO
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = NO
|
||||
DIRECTORY_GRAPH = NO
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
170
docs/man3/qbarray.h.3
Normal file
170
docs/man3/qbarray.h.3
Normal file
@ -0,0 +1,170 @@
|
||||
.TH "qbarray.h" 3 "Sun Mar 11 2012" "Version 0.11.1" "libqb" \" -*- nroff -*-
|
||||
.ad l
|
||||
.nh
|
||||
.SH NAME
|
||||
qbarray.h \-
|
||||
.PP
|
||||
This is a dynamic array (it can grow, but without moving memory)\&.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
.PP
|
||||
\fC#include <stdint\&.h>\fP
|
||||
.br
|
||||
\fC#include <unistd\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbdefs\&.h>\fP
|
||||
.br
|
||||
|
||||
.SS "Typedefs"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "typedef struct qb_array \fBqb_array_t\fP"
|
||||
.br
|
||||
.RI "\fIThis is an opaque data type representing an instance of an array\&. \fP"
|
||||
.in -1c
|
||||
.SS "Functions"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "\fBqb_array_t\fP * \fBqb_array_create\fP (size_t max_elements, size_t element_size)"
|
||||
.br
|
||||
.RI "\fICreate an array with fixed sized elements\&. \fP"
|
||||
.ti -1c
|
||||
.RI "\fBqb_array_t\fP * \fBqb_array_create_2\fP (size_t max_elements, size_t element_size, size_t autogrow_elements)"
|
||||
.br
|
||||
.RI "\fICreate an array with fixed sized elements\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_array_index\fP (\fBqb_array_t\fP *a, int32_t idx, void **element_out)"
|
||||
.br
|
||||
.RI "\fIGet an element at a particular index\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_array_grow\fP (\fBqb_array_t\fP *a, size_t max_elements)"
|
||||
.br
|
||||
.RI "\fIGrow the array\&. \fP"
|
||||
.ti -1c
|
||||
.RI "size_t \fBqb_array_num_bins_get\fP (\fBqb_array_t\fP *a)"
|
||||
.br
|
||||
.RI "\fIGet the number of bins used or the array\&. \fP"
|
||||
.ti -1c
|
||||
.RI "size_t \fBqb_array_elems_per_bin_get\fP (\fBqb_array_t\fP *a)"
|
||||
.br
|
||||
.RI "\fIGet the number of elements per bin\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_array_free\fP (\fBqb_array_t\fP *a)"
|
||||
.br
|
||||
.RI "\fIFree all the memory used by the array\&. \fP"
|
||||
.in -1c
|
||||
.SH "Detailed Description"
|
||||
.PP
|
||||
This is a dynamic array (it can grow, but without moving memory)\&.
|
||||
|
||||
.PP
|
||||
.nf
|
||||
arr = qb_array_create_2(64, sizeof(struct my_struct), 256);
|
||||
\&.\&.\&.
|
||||
res = qb_array_index(arr, idx, (void**)&my_ptr);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
// use my_ptr, now even if there is a grow, this pointer will be valid\&.
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SH "Typedef Documentation"
|
||||
.PP
|
||||
.SS "typedef struct qb_array \fBqb_array_t\fP"
|
||||
|
||||
.PP
|
||||
This is an opaque data type representing an instance of an array\&.
|
||||
.SH "Function Documentation"
|
||||
.PP
|
||||
.SS "\fBqb_array_t\fP* \fBqb_array_create\fP (size_tmax_elements, size_telement_size)"
|
||||
|
||||
.PP
|
||||
Create an array with fixed sized elements\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fImax_elements\fP initial max elements\&.
|
||||
.br
|
||||
\fIelement_size\fP size of each element\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
array instance\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "\fBqb_array_t\fP* \fBqb_array_create_2\fP (size_tmax_elements, size_telement_size, size_tautogrow_elements)"
|
||||
|
||||
.PP
|
||||
Create an array with fixed sized elements\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fImax_elements\fP initial max elements\&.
|
||||
.br
|
||||
\fIelement_size\fP size of each element\&.
|
||||
.br
|
||||
\fIautogrow_elements\fP the number of elements to grow automatically by\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
array instance\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "size_t \fBqb_array_elems_per_bin_get\fP (\fBqb_array_t\fP *a)"
|
||||
|
||||
.PP
|
||||
Get the number of elements per bin\&.
|
||||
.SS "void \fBqb_array_free\fP (\fBqb_array_t\fP *a)"
|
||||
|
||||
.PP
|
||||
Free all the memory used by the array\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIa\fP array instance\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_array_grow\fP (\fBqb_array_t\fP *a, size_tmax_elements)"
|
||||
|
||||
.PP
|
||||
Grow the array\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIa\fP array instance\&.
|
||||
.br
|
||||
\fImax_elements\fP the new maximum size of the array\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(0 == success, else -errno)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_array_index\fP (\fBqb_array_t\fP *a, int32_tidx, void **element_out)"
|
||||
|
||||
.PP
|
||||
Get an element at a particular index\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIa\fP array instance\&.
|
||||
.br
|
||||
\fIidx\fP the index
|
||||
.br
|
||||
\fIelement_out\fP the pointer to the element data\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(0 == success, else -errno)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "size_t \fBqb_array_num_bins_get\fP (\fBqb_array_t\fP *a)"
|
||||
|
||||
.PP
|
||||
Get the number of bins used or the array\&.
|
||||
.SH "Author"
|
||||
.PP
|
||||
Generated automatically by Doxygen for libqb from the source code\&.
|
||||
283
docs/man3/qbatomic.h.3
Normal file
283
docs/man3/qbatomic.h.3
Normal file
@ -0,0 +1,283 @@
|
||||
.TH "qbatomic.h" 3 "Sun Mar 11 2012" "Version 0.11.1" "libqb" \" -*- nroff -*-
|
||||
.ad l
|
||||
.nh
|
||||
.SH NAME
|
||||
qbatomic.h \-
|
||||
.PP
|
||||
Basic atomic integer and pointer operations\&.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
.PP
|
||||
\fC#include <stdint\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbdefs\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbconfig\&.h>\fP
|
||||
.br
|
||||
|
||||
.SS "Defines"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_atomic_int_get\fP(atomic)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_atomic_int_set\fP(atomic, newval)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_atomic_pointer_get\fP(atomic)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_atomic_pointer_set\fP(atomic, newval)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_atomic_int_inc\fP(atomic) (\fBqb_atomic_int_add\fP ((atomic), 1))"
|
||||
.br
|
||||
.RI "\fIAtomically increments the integer pointed to by atomic by 1\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_atomic_int_dec_and_test\fP(atomic) (\fBqb_atomic_int_exchange_and_add\fP ((atomic), -1) == 1)"
|
||||
.br
|
||||
.RI "\fIAtomically decrements the integer pointed to by atomic by 1\&. \fP"
|
||||
.in -1c
|
||||
.SS "Functions"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "void \fBqb_atomic_init\fP (void)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_atomic_int_exchange_and_add\fP (volatile int32_t \fBQB_GNUC_MAY_ALIAS\fP *atomic, int32_t val)"
|
||||
.br
|
||||
.RI "\fIAtomically adds val to the integer pointed to by atomic\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_atomic_int_add\fP (volatile int32_t \fBQB_GNUC_MAY_ALIAS\fP *atomic, int32_t val)"
|
||||
.br
|
||||
.RI "\fIAtomically adds val to the integer pointed to by atomic\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_atomic_int_compare_and_exchange\fP (volatile int32_t \fBQB_GNUC_MAY_ALIAS\fP *atomic, int32_t oldval, int32_t newval)"
|
||||
.br
|
||||
.RI "\fICompares oldval with the integer pointed to by atomic and if they are equal, atomically exchanges *atomic with newval\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_atomic_pointer_compare_and_exchange\fP (volatile void *\fBQB_GNUC_MAY_ALIAS\fP *atomic, void *oldval, void *newval)"
|
||||
.br
|
||||
.RI "\fICompares oldval with the pointer pointed to by atomic and if they are equal, atomically exchanges *atomic with newval\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_atomic_int_get\fP (volatile int32_t \fBQB_GNUC_MAY_ALIAS\fP *atomic)"
|
||||
.br
|
||||
.RI "\fIReads the value of the integer pointed to by atomic\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_atomic_int_set\fP (volatile int32_t \fBQB_GNUC_MAY_ALIAS\fP *atomic, int32_t newval)"
|
||||
.br
|
||||
.RI "\fISets the value of the integer pointed to by atomic\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void * \fBqb_atomic_pointer_get\fP (volatile void *\fBQB_GNUC_MAY_ALIAS\fP *atomic)"
|
||||
.br
|
||||
.RI "\fIReads the value of the pointer pointed to by atomic\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_atomic_pointer_set\fP (volatile void *\fBQB_GNUC_MAY_ALIAS\fP *atomic, void *newval)"
|
||||
.br
|
||||
.RI "\fISets the value of the pointer pointed to by atomic\&. \fP"
|
||||
.in -1c
|
||||
.SH "Detailed Description"
|
||||
.PP
|
||||
Basic atomic integer and pointer operations\&.
|
||||
|
||||
The following functions can be used to atomically access integers and pointers\&. They are implemented as inline assembler function on most platforms and use slower fall-backs otherwise\&. Using them can sometimes save you from using a performance-expensive pthread_mutex to protect the integer or pointer\&.
|
||||
.PP
|
||||
The most important usage is reference counting\&. Using \fBqb_atomic_int_inc()\fP and \fBqb_atomic_int_dec_and_test()\fP makes reference counting a very fast operation\&.
|
||||
.PP
|
||||
You must not directly read integers or pointers concurrently accessed by multiple threads, but use the atomic accessor functions instead\&. That is, always use \fBqb_atomic_int_get()\fP and \fBqb_atomic_pointer_get()\fP for read outs\&. They provide the neccessary synchonization mechanisms like memory barriers to access memory locations concurrently\&.
|
||||
.PP
|
||||
If you are using those functions for anything apart from simple reference counting, you should really be aware of the implications of doing that\&. There are literally thousands of ways to shoot yourself in the foot\&. So if in doubt, use a pthread_mutex\&. If you don't know, what memory barriers are, do not use anything but \fBqb_atomic_int_inc()\fP and \fBqb_atomic_int_dec_and_test()\fP\&.
|
||||
.PP
|
||||
It is not safe to set an integer or pointer just by assigning to it, when it is concurrently accessed by other threads with the following functions\&. Use \fBqb_atomic_int_compare_and_exchange()\fP or \fBqb_atomic_pointer_compare_and_exchange()\fP respectively\&.
|
||||
.SH "Define Documentation"
|
||||
.PP
|
||||
.SS "#define \fBqb_atomic_int_dec_and_test\fP(atomic) (\fBqb_atomic_int_exchange_and_add\fP ((atomic), -1) == 1)"
|
||||
|
||||
.PP
|
||||
Atomically decrements the integer pointed to by atomic by 1\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIatomic\fP a pointer to an integer
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
QB_TRUE if the integer pointed to by atomic is 0 after decrementing it
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "#define \fBqb_atomic_int_get\fP(atomic)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
((void) sizeof (char* [sizeof (*(atomic)) == sizeof (int32_t) ? 1 : -1]), \
|
||||
(qb_atomic_int_get) ((volatile int32_t QB_GNUC_MAY_ALIAS *) (volatile void *) (atomic)))
|
||||
.fi
|
||||
.SS "#define \fBqb_atomic_int_inc\fP(atomic) (\fBqb_atomic_int_add\fP ((atomic), 1))"
|
||||
|
||||
.PP
|
||||
Atomically increments the integer pointed to by atomic by 1\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIatomic\fP a pointer to an integer\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "#define \fBqb_atomic_int_set\fP(atomic, newval)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
((void) sizeof (char* [sizeof (*(atomic)) == sizeof (int32_t) ? 1 : -1]), \
|
||||
(qb_atomic_int_set) ((volatile int32_t QB_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval)))
|
||||
.fi
|
||||
.SS "#define \fBqb_atomic_pointer_get\fP(atomic)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
((void) sizeof (char* [sizeof (*(atomic)) == sizeof (void*) ? 1 : -1]), \
|
||||
(qb_atomic_pointer_get) ((volatile void* QB_GNUC_MAY_ALIAS *) (volatile void *) (atomic)))
|
||||
.fi
|
||||
.SS "#define \fBqb_atomic_pointer_set\fP(atomic, newval)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
((void) sizeof (char* [sizeof (*(atomic)) == sizeof (void*) ? 1 : -1]), \
|
||||
(qb_atomic_pointer_set) ((volatile void* QB_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval)))
|
||||
.fi
|
||||
.SH "Function Documentation"
|
||||
.PP
|
||||
.SS "void \fBqb_atomic_init\fP (void)"
|
||||
|
||||
.SS "void \fBqb_atomic_int_add\fP (volatile int32_t \fBQB_GNUC_MAY_ALIAS\fP *atomic, int32_tval)"
|
||||
|
||||
.PP
|
||||
Atomically adds val to the integer pointed to by atomic\&. Also acts as a memory barrier\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIatomic\fP a pointer to an integer
|
||||
.br
|
||||
\fIval\fP the value to add to *atomic
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_atomic_int_compare_and_exchange\fP (volatile int32_t \fBQB_GNUC_MAY_ALIAS\fP *atomic, int32_toldval, int32_tnewval)"
|
||||
|
||||
.PP
|
||||
Compares oldval with the integer pointed to by atomic and if they are equal, atomically exchanges *atomic with newval\&. Also acts as a memory barrier\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIatomic\fP a pointer to an integer
|
||||
.br
|
||||
\fIoldval\fP the assumed old value of *atomic
|
||||
.br
|
||||
\fInewval\fP the new value of *atomic
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
QB_TRUE, if *atomic was equal oldval\&. QB_FALSE otherwise\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_atomic_int_exchange_and_add\fP (volatile int32_t \fBQB_GNUC_MAY_ALIAS\fP *atomic, int32_tval)"
|
||||
|
||||
.PP
|
||||
Atomically adds val to the integer pointed to by atomic\&. It returns the value of *atomic just before the addition took place\&. Also acts as a memory barrier\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIatomic\fP a pointer to an integer
|
||||
.br
|
||||
\fIval\fP the value to add to *atomic
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
the value of *atomic before the addition\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_atomic_int_get\fP (volatile int32_t \fBQB_GNUC_MAY_ALIAS\fP *atomic)"
|
||||
|
||||
.PP
|
||||
Reads the value of the integer pointed to by atomic\&. Also acts as a memory barrier\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIatomic\fP a pointer to an integer
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
the value of atomic
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_atomic_int_set\fP (volatile int32_t \fBQB_GNUC_MAY_ALIAS\fP *atomic, int32_tnewval)"
|
||||
|
||||
.PP
|
||||
Sets the value of the integer pointed to by atomic\&. Also acts as a memory barrier\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIatomic\fP a pointer to an integer
|
||||
.br
|
||||
\fInewval\fP the new value
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_atomic_pointer_compare_and_exchange\fP (volatile void *\fBQB_GNUC_MAY_ALIAS\fP *atomic, void *oldval, void *newval)"
|
||||
|
||||
.PP
|
||||
Compares oldval with the pointer pointed to by atomic and if they are equal, atomically exchanges *atomic with newval\&. Also acts as a memory barrier\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIatomic\fP a pointer to a void*
|
||||
.br
|
||||
\fIoldval\fP the assumed old value of *atomic
|
||||
.br
|
||||
\fInewval\fP the new value of *atomic
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
QB_TRUE if atomic was equal oldval, else QB_FALSE\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void* \fBqb_atomic_pointer_get\fP (volatile void *\fBQB_GNUC_MAY_ALIAS\fP *atomic)"
|
||||
|
||||
.PP
|
||||
Reads the value of the pointer pointed to by atomic\&. Also acts as a memory barrier\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIatomic\fP a pointer to a void*\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
the value to add to atomic\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_atomic_pointer_set\fP (volatile void *\fBQB_GNUC_MAY_ALIAS\fP *atomic, void *newval)"
|
||||
|
||||
.PP
|
||||
Sets the value of the pointer pointed to by atomic\&. Also acts as a memory barrier\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIatomic\fP a pointer to a void*
|
||||
.br
|
||||
\fInewval\fP the new value
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SH "Author"
|
||||
.PP
|
||||
Generated automatically by Doxygen for libqb from the source code\&.
|
||||
303
docs/man3/qbhdb.h.3
Normal file
303
docs/man3/qbhdb.h.3
Normal file
@ -0,0 +1,303 @@
|
||||
.TH "qbhdb.h" 3 "Sun Mar 11 2012" "Version 0.11.1" "libqb" \" -*- nroff -*-
|
||||
.ad l
|
||||
.nh
|
||||
.SH NAME
|
||||
qbhdb.h \-
|
||||
.PP
|
||||
The handle database is for reference counting objects\&.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
.PP
|
||||
\fC#include <stdlib\&.h>\fP
|
||||
.br
|
||||
\fC#include <stdint\&.h>\fP
|
||||
.br
|
||||
\fC#include <inttypes\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbarray\&.h>\fP
|
||||
.br
|
||||
|
||||
.SS "Data Structures"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_hdb_handle\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_hdb\fP"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Defines"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "#define \fB_GNU_SOURCE\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_HDB_D_FORMAT\fP '%'PRIu64"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_HDB_X_FORMAT\fP '%'PRIx64"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_HDB_DECLARE\fP(database_name, destructor_function)"
|
||||
.br
|
||||
.RI "\fIConvience macro for declaring a file scoped handle database\&. \fP"
|
||||
.in -1c
|
||||
.SS "Typedefs"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "typedef uint64_t \fBqb_handle_t\fP"
|
||||
.br
|
||||
.RI "\fIGeneric handle type is 64 bits\&. \fP"
|
||||
.in -1c
|
||||
.SS "Functions"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "void \fBqb_hdb_create\fP (struct \fBqb_hdb\fP *hdb)"
|
||||
.br
|
||||
.RI "\fICreate a new database\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_hdb_destroy\fP (struct \fBqb_hdb\fP *hdb)"
|
||||
.br
|
||||
.RI "\fIDestroy a handle database\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_hdb_handle_create\fP (struct \fBqb_hdb\fP *hdb, int32_t instance_size, \fBqb_handle_t\fP *handle_id_out)"
|
||||
.br
|
||||
.RI "\fICreate a new handle\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_hdb_handle_get\fP (struct \fBqb_hdb\fP *hdb, \fBqb_handle_t\fP handle_in, void **instance)"
|
||||
.br
|
||||
.RI "\fIGet the instance associated with this handle and increase it's refcount\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_hdb_handle_get_always\fP (struct \fBqb_hdb\fP *hdb, \fBqb_handle_t\fP handle_in, void **instance)"
|
||||
.br
|
||||
.RI "\fIGet the instance associated with this handle and increase it's refcount\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_hdb_handle_put\fP (struct \fBqb_hdb\fP *hdb, \fBqb_handle_t\fP handle_in)"
|
||||
.br
|
||||
.RI "\fIPut the instance associated with this handle and decrease it's refcount\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_hdb_handle_destroy\fP (struct \fBqb_hdb\fP *hdb, \fBqb_handle_t\fP handle_in)"
|
||||
.br
|
||||
.RI "\fIRequest the destruction of the object\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_hdb_handle_refcount_get\fP (struct \fBqb_hdb\fP *hdb, \fBqb_handle_t\fP handle_in)"
|
||||
.br
|
||||
.RI "\fIGet the current refcount\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_hdb_iterator_reset\fP (struct \fBqb_hdb\fP *hdb)"
|
||||
.br
|
||||
.RI "\fIReset the iterator\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_hdb_iterator_next\fP (struct \fBqb_hdb\fP *hdb, void **instance, \fBqb_handle_t\fP *handle)"
|
||||
.br
|
||||
.RI "\fIGet the next object and increament it's refcount\&. \fP"
|
||||
.ti -1c
|
||||
.RI "uint32_t \fBqb_hdb_base_convert\fP (\fBqb_handle_t\fP handle)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "uint64_t \fBqb_hdb_nocheck_convert\fP (uint32_t handle)"
|
||||
.br
|
||||
.in -1c
|
||||
.SH "Detailed Description"
|
||||
.PP
|
||||
The handle database is for reference counting objects\&.
|
||||
|
||||
|
||||
.SH "Define Documentation"
|
||||
.PP
|
||||
.SS "#define \fB_GNU_SOURCE\fP"
|
||||
|
||||
.SS "#define \fBQB_HDB_D_FORMAT\fP '%'PRIu64"
|
||||
|
||||
.SS "#define \fBQB_HDB_DECLARE\fP(database_name, destructor_function)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
static struct qb_hdb (database_name) = { \
|
||||
\&.handle_count = 0, \
|
||||
\&.handles = NULL, \
|
||||
\&.iterator = 0, \
|
||||
\&.destructor = destructor_function, \
|
||||
\&.first_run = 1 \
|
||||
}; \
|
||||
.fi
|
||||
.PP
|
||||
Convience macro for declaring a file scoped handle database\&. .PP
|
||||
.nf
|
||||
QB_HDB_DECLARE(my_handle_database, NULL);
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SS "#define \fBQB_HDB_X_FORMAT\fP '%'PRIx64"
|
||||
|
||||
.SH "Typedef Documentation"
|
||||
.PP
|
||||
.SS "typedef uint64_t \fBqb_handle_t\fP"
|
||||
|
||||
.PP
|
||||
Generic handle type is 64 bits\&.
|
||||
.SH "Function Documentation"
|
||||
.PP
|
||||
.SS "uint32_t \fBqb_hdb_base_convert\fP (\fBqb_handle_t\fPhandle)"
|
||||
|
||||
.SS "void \fBqb_hdb_create\fP (struct \fBqb_hdb\fP *hdb)"
|
||||
|
||||
.PP
|
||||
Create a new database\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhdb\fP the database to init\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_hdb_destroy\fP (struct \fBqb_hdb\fP *hdb)"
|
||||
|
||||
.PP
|
||||
Destroy a handle database\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhdb\fP the database to destroy\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_hdb_handle_create\fP (struct \fBqb_hdb\fP *hdb, int32_tinstance_size, \fBqb_handle_t\fP *handle_id_out)"
|
||||
|
||||
.PP
|
||||
Create a new handle\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhdb\fP the database instance
|
||||
.br
|
||||
\fIinstance_size\fP size of the object to malloc
|
||||
.br
|
||||
\fIhandle_id_out\fP new handle
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(0 == ok, -errno faliure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_hdb_handle_destroy\fP (struct \fBqb_hdb\fP *hdb, \fBqb_handle_t\fPhandle_in)"
|
||||
|
||||
.PP
|
||||
Request the destruction of the object\&. When the refcount is 0, it will be destroyed\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhandle_in\fP the handle
|
||||
.br
|
||||
\fIhdb\fP the database instance
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(0 == ok, -errno faliure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_hdb_handle_get\fP (struct \fBqb_hdb\fP *hdb, \fBqb_handle_t\fPhandle_in, void **instance)"
|
||||
|
||||
.PP
|
||||
Get the instance associated with this handle and increase it's refcount\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhandle_in\fP the handle
|
||||
.br
|
||||
\fIhdb\fP the database instance
|
||||
.br
|
||||
\fIinstance\fP (out) pointer to the desired object\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(0 == ok, -errno faliure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_hdb_handle_get_always\fP (struct \fBqb_hdb\fP *hdb, \fBqb_handle_t\fPhandle_in, void **instance)"
|
||||
|
||||
.PP
|
||||
Get the instance associated with this handle and increase it's refcount\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhandle_in\fP the handle
|
||||
.br
|
||||
\fIhdb\fP the database instance
|
||||
.br
|
||||
\fIinstance\fP (out) pointer to the desired object\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(0 == ok, -errno faliure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_hdb_handle_put\fP (struct \fBqb_hdb\fP *hdb, \fBqb_handle_t\fPhandle_in)"
|
||||
|
||||
.PP
|
||||
Put the instance associated with this handle and decrease it's refcount\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhandle_in\fP the handle
|
||||
.br
|
||||
\fIhdb\fP the database instance
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(0 == ok, -errno faliure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_hdb_handle_refcount_get\fP (struct \fBqb_hdb\fP *hdb, \fBqb_handle_t\fPhandle_in)"
|
||||
|
||||
.PP
|
||||
Get the current refcount\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhandle_in\fP the handle
|
||||
.br
|
||||
\fIhdb\fP the database instance
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(>= 0 is the refcount, -errno faliure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_hdb_iterator_next\fP (struct \fBqb_hdb\fP *hdb, void **instance, \fBqb_handle_t\fP *handle)"
|
||||
|
||||
.PP
|
||||
Get the next object and increament it's refcount\&. Remember to call \fBqb_hdb_handle_put()\fP
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhdb\fP the database instance
|
||||
.br
|
||||
\fIhandle\fP (out) the handle
|
||||
.br
|
||||
\fIinstance\fP (out) pointer to the desired object\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(0 == ok, -errno faliure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_hdb_iterator_reset\fP (struct \fBqb_hdb\fP *hdb)"
|
||||
|
||||
.PP
|
||||
Reset the iterator\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhdb\fP the database instance
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "uint64_t \fBqb_hdb_nocheck_convert\fP (uint32_thandle)"
|
||||
|
||||
.SH "Author"
|
||||
.PP
|
||||
Generated automatically by Doxygen for libqb from the source code\&.
|
||||
100
docs/man3/qbipc_common.h.3
Normal file
100
docs/man3/qbipc_common.h.3
Normal file
@ -0,0 +1,100 @@
|
||||
.TH "qbipc_common.h" 3 "Sun Mar 11 2012" "Version 0.11.1" "libqb" \" -*- nroff -*-
|
||||
.ad l
|
||||
.nh
|
||||
.SH NAME
|
||||
qbipc_common.h \-
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
.PP
|
||||
\fC#include <stdint\&.h>\fP
|
||||
.br
|
||||
|
||||
.SS "Data Structures"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_ipc_request_header\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_ipc_response_header\fP"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Defines"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_IPC_MSG_NEW_MESSAGE\fP 0"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_IPC_MSG_USER_START\fP \fBQB_IPC_MSG_NEW_MESSAGE\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_IPC_MSG_AUTHENTICATE\fP -1"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_IPC_MSG_NEW_EVENT_SOCK\fP -2"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_IPC_MSG_DISCONNECT\fP -3"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Enumerations"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "enum \fBqb_ipc_type\fP { \fBQB_IPC_SOCKET\fP, \fBQB_IPC_SHM\fP, \fBQB_IPC_POSIX_MQ\fP, \fBQB_IPC_SYSV_MQ\fP }"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Functions"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_ipc_request_header\fP \fB__attribute__\fP ((aligned(8)))"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Variables"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "enum \fBqb_ipc_type\fP \fB__attribute__\fP"
|
||||
.br
|
||||
.in -1c
|
||||
.SH "Define Documentation"
|
||||
.PP
|
||||
.SS "#define \fBQB_IPC_MSG_AUTHENTICATE\fP -1"
|
||||
|
||||
.SS "#define \fBQB_IPC_MSG_DISCONNECT\fP -3"
|
||||
|
||||
.SS "#define \fBQB_IPC_MSG_NEW_EVENT_SOCK\fP -2"
|
||||
|
||||
.SS "#define \fBQB_IPC_MSG_NEW_MESSAGE\fP 0"
|
||||
|
||||
.SS "#define \fBQB_IPC_MSG_USER_START\fP \fBQB_IPC_MSG_NEW_MESSAGE\fP"
|
||||
|
||||
.SH "Enumeration Type Documentation"
|
||||
.PP
|
||||
.SS "enum \fBqb_ipc_type\fP"
|
||||
|
||||
.PP
|
||||
\fBEnumerator: \fP
|
||||
.in +1c
|
||||
.TP
|
||||
\fB\fIQB_IPC_SOCKET \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_IPC_SHM \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_IPC_POSIX_MQ \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_IPC_SYSV_MQ \fP\fP
|
||||
|
||||
.SH "Function Documentation"
|
||||
.PP
|
||||
.SS "struct \fBqb_ipc_request_header\fP \fB__attribute__\fP ((aligned(8)))"
|
||||
|
||||
.SH "Variable Documentation"
|
||||
.PP
|
||||
.SS "int32_t error \fB__attribute__\fP"
|
||||
|
||||
.SH "Author"
|
||||
.PP
|
||||
Generated automatically by Doxygen for libqb from the source code\&.
|
||||
302
docs/man3/qbipcc.h.3
Normal file
302
docs/man3/qbipcc.h.3
Normal file
@ -0,0 +1,302 @@
|
||||
.TH "qbipcc.h" 3 "Sun Mar 11 2012" "Version 0.11.1" "libqb" \" -*- nroff -*-
|
||||
.ad l
|
||||
.nh
|
||||
.SH NAME
|
||||
qbipcc.h \-
|
||||
.PP
|
||||
Client IPC API\&.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
.PP
|
||||
\fC#include <qb/qbconfig\&.h>\fP
|
||||
.br
|
||||
\fC#include <pthread\&.h>\fP
|
||||
.br
|
||||
\fC#include <sys/poll\&.h>\fP
|
||||
.br
|
||||
\fC#include <sys/socket\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbhdb\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbipc_common\&.h>\fP
|
||||
.br
|
||||
|
||||
.SS "Typedefs"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "typedef struct qb_ipcc_connection \fBqb_ipcc_connection_t\fP"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Functions"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "\fBqb_ipcc_connection_t\fP * \fBqb_ipcc_connect\fP (const char *name, size_t max_msg_size)"
|
||||
.br
|
||||
.RI "\fICreate a connection to an IPC service\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_ipcc_disconnect\fP (\fBqb_ipcc_connection_t\fP *c)"
|
||||
.br
|
||||
.RI "\fIDisconnect an IPC connection\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_ipcc_fd_get\fP (\fBqb_ipcc_connection_t\fP *c, int32_t *fd)"
|
||||
.br
|
||||
.RI "\fIGet the file descriptor to poll\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_ipcc_fc_enable_max_set\fP (\fBqb_ipcc_connection_t\fP *c, uint32_t max)"
|
||||
.br
|
||||
.RI "\fISet the maximum allowable flowcontrol value\&. \fP"
|
||||
.ti -1c
|
||||
.RI "ssize_t \fBqb_ipcc_send\fP (\fBqb_ipcc_connection_t\fP *c, const void *msg_ptr, size_t msg_len)"
|
||||
.br
|
||||
.RI "\fISend a message\&. \fP"
|
||||
.ti -1c
|
||||
.RI "ssize_t \fBqb_ipcc_sendv\fP (\fBqb_ipcc_connection_t\fP *c, const struct iovec *iov, size_t iov_len)"
|
||||
.br
|
||||
.RI "\fISend a message (iovec)\&. \fP"
|
||||
.ti -1c
|
||||
.RI "ssize_t \fBqb_ipcc_recv\fP (\fBqb_ipcc_connection_t\fP *c, void *msg_ptr, size_t msg_len, int32_t ms_timeout)"
|
||||
.br
|
||||
.RI "\fIReceive a response\&. \fP"
|
||||
.ti -1c
|
||||
.RI "ssize_t \fBqb_ipcc_sendv_recv\fP (\fBqb_ipcc_connection_t\fP *c, const struct iovec *iov, uint32_t iov_len, void *msg_ptr, size_t msg_len, int32_t ms_timeout)"
|
||||
.br
|
||||
.RI "\fIThis is a convenience function that simply sends and then recvs\&. \fP"
|
||||
.ti -1c
|
||||
.RI "ssize_t \fBqb_ipcc_event_recv\fP (\fBqb_ipcc_connection_t\fP *c, void *msg_ptr, size_t msg_len, int32_t ms_timeout)"
|
||||
.br
|
||||
.RI "\fIReceive an event\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_ipcc_context_set\fP (\fBqb_ipcc_connection_t\fP *c, void *context)"
|
||||
.br
|
||||
.RI "\fIAssociate a 'user' pointer with this connection\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void * \fBqb_ipcc_context_get\fP (\fBqb_ipcc_connection_t\fP *c)"
|
||||
.br
|
||||
.RI "\fIGet the context (set previously) \fP"
|
||||
.in -1c
|
||||
.SH "Detailed Description"
|
||||
.PP
|
||||
Client IPC API\&.
|
||||
|
||||
\fBLifecycle of an IPC connection\&.\fP
|
||||
.RS 4
|
||||
An IPC connection is made to the server with \fBqb_ipcc_connect()\fP\&. This function connects to the server and requests channels be created for communication\&. To disconnect, the client either exits or executes the function \fBqb_ipcc_disconnect()\fP\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBSynchronous communication\fP
|
||||
.RS 4
|
||||
The function \fBqb_ipcc_sendv_recv()\fP sends an iovector request and receives a response\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBAsynchronous requests from the client\fP
|
||||
.RS 4
|
||||
The function \fBqb_ipcc_sendv()\fP sends an iovector request\&. The function \fBqb_ipcc_send()\fP sends an message buffer request\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBAsynchronous events from the server\fP
|
||||
.RS 4
|
||||
The \fBqb_ipcc_event_recv()\fP function receives an out-of-band asyncronous message\&. The asynchronous messages are queued and can provide very high out-of-band performance\&. To determine when to call \fBqb_ipcc_event_recv()\fP the \fBqb_ipcc_fd_get()\fP call is used to obtain a file descriptor used in the poll() or select() system calls\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SH "Typedef Documentation"
|
||||
.PP
|
||||
.SS "typedef struct qb_ipcc_connection \fBqb_ipcc_connection_t\fP"
|
||||
|
||||
.SH "Function Documentation"
|
||||
.PP
|
||||
.SS "\fBqb_ipcc_connection_t\fP* \fBqb_ipcc_connect\fP (const char *name, size_tmax_msg_size)"
|
||||
|
||||
.PP
|
||||
Create a connection to an IPC service\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIname\fP name of the service\&.
|
||||
.br
|
||||
\fImax_msg_size\fP biggest msg size\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
NULL (error: see errno) or a connection object\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void* \fBqb_ipcc_context_get\fP (\fBqb_ipcc_connection_t\fP *c)"
|
||||
|
||||
.PP
|
||||
Get the context (set previously) \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
the context
|
||||
.RE
|
||||
.PP
|
||||
\fBSee also:\fP
|
||||
.RS 4
|
||||
\fBqb_ipcc_context_set()\fP
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_ipcc_context_set\fP (\fBqb_ipcc_connection_t\fP *c, void *context)"
|
||||
|
||||
.PP
|
||||
Associate a 'user' pointer with this connection\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIcontext\fP the point to associate with this connection\&.
|
||||
.br
|
||||
\fIc\fP connection instance
|
||||
.RE
|
||||
.PP
|
||||
\fBSee also:\fP
|
||||
.RS 4
|
||||
\fBqb_ipcc_context_get()\fP
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_ipcc_disconnect\fP (\fBqb_ipcc_connection_t\fP *c)"
|
||||
|
||||
.PP
|
||||
Disconnect an IPC connection\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "ssize_t \fBqb_ipcc_event_recv\fP (\fBqb_ipcc_connection_t\fP *c, void *msg_ptr, size_tmsg_len, int32_tms_timeout)"
|
||||
|
||||
.PP
|
||||
Receive an event\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.br
|
||||
\fImsg_ptr\fP pointer to a message buffer to receive into
|
||||
.br
|
||||
\fImsg_len\fP the size of the buffer
|
||||
.br
|
||||
\fIms_timeout\fP time in milli seconds to wait for a message 0 == no wait, negative == block, positive == wait X ms\&.
|
||||
.br
|
||||
\fIms_timeout\fP max time to wait for a response
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
size of the message or error (-errno)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_ipcc_fc_enable_max_set\fP (\fBqb_ipcc_connection_t\fP *c, uint32_tmax)"
|
||||
|
||||
.PP
|
||||
Set the maximum allowable flowcontrol value\&. \fBNote:\fP
|
||||
.RS 4
|
||||
the default is 1
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.br
|
||||
\fImax\fP the max allowable flowcontrol value (1 or 2)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_ipcc_fd_get\fP (\fBqb_ipcc_connection_t\fP *c, int32_t *fd)"
|
||||
|
||||
.PP
|
||||
Get the file descriptor to poll\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.br
|
||||
\fIfd\fP (out) file descriptor to poll
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "ssize_t \fBqb_ipcc_recv\fP (\fBqb_ipcc_connection_t\fP *c, void *msg_ptr, size_tmsg_len, int32_tms_timeout)"
|
||||
|
||||
.PP
|
||||
Receive a response\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.br
|
||||
\fImsg_ptr\fP pointer to a message buffer to receive into
|
||||
.br
|
||||
\fImsg_len\fP the size of the buffer
|
||||
.br
|
||||
\fIms_timeout\fP max time to wait for a response
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(size recv'ed, -errno == error)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "ssize_t \fBqb_ipcc_send\fP (\fBqb_ipcc_connection_t\fP *c, const void *msg_ptr, size_tmsg_len)"
|
||||
|
||||
.PP
|
||||
Send a message\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.br
|
||||
\fImsg_ptr\fP pointer to a message to send
|
||||
.br
|
||||
\fImsg_len\fP the size of the message
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(size sent, -errno == error)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "ssize_t \fBqb_ipcc_sendv\fP (\fBqb_ipcc_connection_t\fP *c, const struct iovec *iov, size_tiov_len)"
|
||||
|
||||
.PP
|
||||
Send a message (iovec)\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.br
|
||||
\fIiov\fP pointer to an iovec struct to send
|
||||
.br
|
||||
\fIiov_len\fP the number of iovecs used
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
(size sent, -errno == error)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "ssize_t \fBqb_ipcc_sendv_recv\fP (\fBqb_ipcc_connection_t\fP *c, const struct iovec *iov, uint32_tiov_len, void *msg_ptr, size_tmsg_len, int32_tms_timeout)"
|
||||
|
||||
.PP
|
||||
This is a convenience function that simply sends and then recvs\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.br
|
||||
\fIiov\fP pointer to an iovec struct to send
|
||||
.br
|
||||
\fIiov_len\fP the number of iovecs used
|
||||
.br
|
||||
\fImsg_ptr\fP pointer to a message buffer to receive into
|
||||
.br
|
||||
\fImsg_len\fP the size of the buffer
|
||||
.br
|
||||
\fIms_timeout\fP max time to wait for a response
|
||||
.RE
|
||||
.PP
|
||||
\fBSee also:\fP
|
||||
.RS 4
|
||||
\fBqb_ipcc_sendv()\fP \fBqb_ipcc_recv()\fP
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SH "Author"
|
||||
.PP
|
||||
Generated automatically by Doxygen for libqb from the source code\&.
|
||||
558
docs/man3/qbipcs.h.3
Normal file
558
docs/man3/qbipcs.h.3
Normal file
@ -0,0 +1,558 @@
|
||||
.TH "qbipcs.h" 3 "Sun Mar 11 2012" "Version 0.11.1" "libqb" \" -*- nroff -*-
|
||||
.ad l
|
||||
.nh
|
||||
.SH NAME
|
||||
qbipcs.h \-
|
||||
.PP
|
||||
Server IPC API\&.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
.PP
|
||||
\fC#include <stdlib\&.h>\fP
|
||||
.br
|
||||
\fC#include <sys/uio\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbipc_common\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbhdb\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbloop\&.h>\fP
|
||||
.br
|
||||
|
||||
.SS "Data Structures"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_ipcs_stats\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_ipcs_connection_stats\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_ipcs_poll_handlers\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_ipcs_service_handlers\fP"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Typedefs"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "typedef struct qb_ipcs_connection \fBqb_ipcs_connection_t\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef struct qb_ipcs_service \fBqb_ipcs_service_t\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef int32_t(* \fBqb_ipcs_dispatch_fn_t\fP )(int32_t fd, int32_t revents, void *data)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef int32_t(* \fBqb_ipcs_dispatch_add_fn\fP )(enum \fBqb_loop_priority\fP p, int32_t fd, int32_t events, void *data, \fBqb_ipcs_dispatch_fn_t\fP fn)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef int32_t(* \fBqb_ipcs_dispatch_mod_fn\fP )(enum \fBqb_loop_priority\fP p, int32_t fd, int32_t events, void *data, \fBqb_ipcs_dispatch_fn_t\fP fn)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef int32_t(* \fBqb_ipcs_dispatch_del_fn\fP )(int32_t fd)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef int32_t(* \fBqb_ipcs_job_add_fn\fP )(enum \fBqb_loop_priority\fP p, void *data, \fBqb_loop_job_dispatch_fn\fP dispatch_fn)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef int32_t(* \fBqb_ipcs_connection_accept_fn\fP )(\fBqb_ipcs_connection_t\fP *c, uid_t uid, gid_t gid)"
|
||||
.br
|
||||
.RI "\fIThis callback is to check wether you want to accept a new connection\&. \fP"
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_ipcs_connection_created_fn\fP )(\fBqb_ipcs_connection_t\fP *c)"
|
||||
.br
|
||||
.RI "\fIThis is called after a new connection has been created\&. \fP"
|
||||
.ti -1c
|
||||
.RI "typedef int32_t(* \fBqb_ipcs_connection_closed_fn\fP )(\fBqb_ipcs_connection_t\fP *c)"
|
||||
.br
|
||||
.RI "\fIThis is called after a connection has been disconnected\&. \fP"
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_ipcs_connection_destroyed_fn\fP )(\fBqb_ipcs_connection_t\fP *c)"
|
||||
.br
|
||||
.RI "\fIThis is called just before a connection is freed\&. \fP"
|
||||
.ti -1c
|
||||
.RI "typedef int32_t(* \fBqb_ipcs_msg_process_fn\fP )(\fBqb_ipcs_connection_t\fP *c, void *data, size_t size)"
|
||||
.br
|
||||
.RI "\fIThis is the message processing calback\&. \fP"
|
||||
.in -1c
|
||||
.SS "Enumerations"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "enum \fBqb_ipcs_rate_limit\fP { \fBQB_IPCS_RATE_FAST\fP, \fBQB_IPCS_RATE_NORMAL\fP, \fBQB_IPCS_RATE_SLOW\fP, \fBQB_IPCS_RATE_OFF\fP, \fBQB_IPCS_RATE_OFF_2\fP }"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Functions"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "\fBqb_ipcs_service_t\fP * \fBqb_ipcs_create\fP (const char *name, int32_t service_id, enum \fBqb_ipc_type\fP type, struct \fBqb_ipcs_service_handlers\fP *handlers)"
|
||||
.br
|
||||
.RI "\fICreate a new IPC server\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_ipcs_ref\fP (\fBqb_ipcs_service_t\fP *s)"
|
||||
.br
|
||||
.RI "\fIIncrease the reference counter on the service object\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_ipcs_unref\fP (\fBqb_ipcs_service_t\fP *s)"
|
||||
.br
|
||||
.RI "\fIDecrease the reference counter on the service object\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_ipcs_poll_handlers_set\fP (\fBqb_ipcs_service_t\fP *s, struct \fBqb_ipcs_poll_handlers\fP *handlers)"
|
||||
.br
|
||||
.RI "\fISet your poll callbacks\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_ipcs_run\fP (\fBqb_ipcs_service_t\fP *s)"
|
||||
.br
|
||||
.RI "\fIrun the new IPC server\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_ipcs_destroy\fP (\fBqb_ipcs_service_t\fP *s)"
|
||||
.br
|
||||
.RI "\fIDestroy the IPC server\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_ipcs_request_rate_limit\fP (\fBqb_ipcs_service_t\fP *s, enum \fBqb_ipcs_rate_limit\fP rl)"
|
||||
.br
|
||||
.RI "\fILimit the incomming request rate\&. \fP"
|
||||
.ti -1c
|
||||
.RI "ssize_t \fBqb_ipcs_response_send\fP (\fBqb_ipcs_connection_t\fP *c, const void *data, size_t size)"
|
||||
.br
|
||||
.RI "\fISend a response to a incomming request\&. \fP"
|
||||
.ti -1c
|
||||
.RI "ssize_t \fBqb_ipcs_response_sendv\fP (\fBqb_ipcs_connection_t\fP *c, const struct iovec *iov, size_t iov_len)"
|
||||
.br
|
||||
.RI "\fISend a response to a incomming request\&. \fP"
|
||||
.ti -1c
|
||||
.RI "ssize_t \fBqb_ipcs_event_send\fP (\fBqb_ipcs_connection_t\fP *c, const void *data, size_t size)"
|
||||
.br
|
||||
.RI "\fISend an asyncronous event message to the client\&. \fP"
|
||||
.ti -1c
|
||||
.RI "ssize_t \fBqb_ipcs_event_sendv\fP (\fBqb_ipcs_connection_t\fP *c, const struct iovec *iov, size_t iov_len)"
|
||||
.br
|
||||
.RI "\fISend an asyncronous event message to the client\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_ipcs_connection_ref\fP (\fBqb_ipcs_connection_t\fP *c)"
|
||||
.br
|
||||
.RI "\fIIncrement the connection's reference counter\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_ipcs_connection_unref\fP (\fBqb_ipcs_connection_t\fP *c)"
|
||||
.br
|
||||
.RI "\fIDecrement the connection's reference counter\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_ipcs_disconnect\fP (\fBqb_ipcs_connection_t\fP *c)"
|
||||
.br
|
||||
.RI "\fIDisconnect from this client\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_ipcs_service_id_get\fP (\fBqb_ipcs_connection_t\fP *c)"
|
||||
.br
|
||||
.RI "\fIGet the service id related to this connection's service\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_ipcs_context_set\fP (\fBqb_ipcs_connection_t\fP *c, void *context)"
|
||||
.br
|
||||
.RI "\fIAssociate a 'user' pointer with this connection\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void * \fBqb_ipcs_context_get\fP (\fBqb_ipcs_connection_t\fP *c)"
|
||||
.br
|
||||
.RI "\fIGet the context (set previously) \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_ipcs_connection_stats_get\fP (\fBqb_ipcs_connection_t\fP *c, struct \fBqb_ipcs_connection_stats\fP *stats, int32_t clear_after_read)"
|
||||
.br
|
||||
.RI "\fIGet the connection statistics\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_ipcs_stats_get\fP (\fBqb_ipcs_service_t\fP *pt, struct \fBqb_ipcs_stats\fP *stats, int32_t clear_after_read)"
|
||||
.br
|
||||
.RI "\fIGet the service statistics\&. \fP"
|
||||
.ti -1c
|
||||
.RI "\fBqb_ipcs_connection_t\fP * \fBqb_ipcs_connection_first_get\fP (\fBqb_ipcs_service_t\fP *pt)"
|
||||
.br
|
||||
.RI "\fIGet the first connection\&. \fP"
|
||||
.ti -1c
|
||||
.RI "\fBqb_ipcs_connection_t\fP * \fBqb_ipcs_connection_next_get\fP (\fBqb_ipcs_service_t\fP *pt, \fBqb_ipcs_connection_t\fP *current)"
|
||||
.br
|
||||
.RI "\fIGet the next connection\&. \fP"
|
||||
.in -1c
|
||||
.SH "Detailed Description"
|
||||
.PP
|
||||
Server IPC API\&.
|
||||
|
||||
|
||||
.SH "Typedef Documentation"
|
||||
.PP
|
||||
.SS "typedef int32_t(* \fBqb_ipcs_connection_accept_fn\fP)(\fBqb_ipcs_connection_t\fP *c, uid_t uid, gid_t gid)"
|
||||
|
||||
.PP
|
||||
This callback is to check wether you want to accept a new connection\&. The type of checks you should do are authentication, service availabilty or process resource constraints\&.
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
0 to accept or -errno to indicate a failure (sent back to the client)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "typedef int32_t(* \fBqb_ipcs_connection_closed_fn\fP)(\fBqb_ipcs_connection_t\fP *c)"
|
||||
|
||||
.PP
|
||||
This is called after a connection has been disconnected\&. \fBNote:\fP
|
||||
.RS 4
|
||||
if you return anything but 0 this function will be repeativily called (until 0 is returned)\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "typedef void(* \fBqb_ipcs_connection_created_fn\fP)(\fBqb_ipcs_connection_t\fP *c)"
|
||||
|
||||
.PP
|
||||
This is called after a new connection has been created\&.
|
||||
.SS "typedef void(* \fBqb_ipcs_connection_destroyed_fn\fP)(\fBqb_ipcs_connection_t\fP *c)"
|
||||
|
||||
.PP
|
||||
This is called just before a connection is freed\&.
|
||||
.SS "typedef struct qb_ipcs_connection \fBqb_ipcs_connection_t\fP"
|
||||
|
||||
.SS "typedef int32_t(* \fBqb_ipcs_dispatch_add_fn\fP)(enum \fBqb_loop_priority\fP p, int32_t fd, int32_t events, void *data, \fBqb_ipcs_dispatch_fn_t\fP fn)"
|
||||
|
||||
.SS "typedef int32_t(* \fBqb_ipcs_dispatch_del_fn\fP)(int32_t fd)"
|
||||
|
||||
.SS "typedef int32_t(* \fBqb_ipcs_dispatch_fn_t\fP)(int32_t fd, int32_t revents, void *data)"
|
||||
|
||||
.SS "typedef int32_t(* \fBqb_ipcs_dispatch_mod_fn\fP)(enum \fBqb_loop_priority\fP p, int32_t fd, int32_t events, void *data, \fBqb_ipcs_dispatch_fn_t\fP fn)"
|
||||
|
||||
.SS "typedef int32_t(* \fBqb_ipcs_job_add_fn\fP)(enum \fBqb_loop_priority\fP p, void *data, \fBqb_loop_job_dispatch_fn\fP dispatch_fn)"
|
||||
|
||||
.SS "typedef int32_t(* \fBqb_ipcs_msg_process_fn\fP)(\fBqb_ipcs_connection_t\fP *c, void *data, size_t size)"
|
||||
|
||||
.PP
|
||||
This is the message processing calback\&. It is called with the message data\&.
|
||||
.SS "typedef struct qb_ipcs_service \fBqb_ipcs_service_t\fP"
|
||||
|
||||
.SH "Enumeration Type Documentation"
|
||||
.PP
|
||||
.SS "enum \fBqb_ipcs_rate_limit\fP"
|
||||
|
||||
.PP
|
||||
\fBEnumerator: \fP
|
||||
.in +1c
|
||||
.TP
|
||||
\fB\fIQB_IPCS_RATE_FAST \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_IPCS_RATE_NORMAL \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_IPCS_RATE_SLOW \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_IPCS_RATE_OFF \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_IPCS_RATE_OFF_2 \fP\fP
|
||||
|
||||
.SH "Function Documentation"
|
||||
.PP
|
||||
.SS "\fBqb_ipcs_connection_t\fP* \fBqb_ipcs_connection_first_get\fP (\fBqb_ipcs_service_t\fP *pt)"
|
||||
|
||||
.PP
|
||||
Get the first connection\&. \fBNote:\fP
|
||||
.RS 4
|
||||
call qb_ipcs_connection_ref_dec() after using the connection\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpt\fP service instance
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
first connection
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "\fBqb_ipcs_connection_t\fP* \fBqb_ipcs_connection_next_get\fP (\fBqb_ipcs_service_t\fP *pt, \fBqb_ipcs_connection_t\fP *current)"
|
||||
|
||||
.PP
|
||||
Get the next connection\&. \fBNote:\fP
|
||||
.RS 4
|
||||
call qb_ipcs_connection_ref_dec() after using the connection\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpt\fP service instance
|
||||
.br
|
||||
\fIcurrent\fP current connection
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
next connection
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_ipcs_connection_ref\fP (\fBqb_ipcs_connection_t\fP *c)"
|
||||
|
||||
.PP
|
||||
Increment the connection's reference counter\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_ipcs_connection_stats_get\fP (\fBqb_ipcs_connection_t\fP *c, struct \fBqb_ipcs_connection_stats\fP *stats, int32_tclear_after_read)"
|
||||
|
||||
.PP
|
||||
Get the connection statistics\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIstats\fP (out) the statistics structure
|
||||
.br
|
||||
\fIclear_after_read\fP clear stats after copying them into stats
|
||||
.br
|
||||
\fIc\fP connection instance
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
0 == ok; -errno to indicate a failure
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_ipcs_connection_unref\fP (\fBqb_ipcs_connection_t\fP *c)"
|
||||
|
||||
.PP
|
||||
Decrement the connection's reference counter\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void* \fBqb_ipcs_context_get\fP (\fBqb_ipcs_connection_t\fP *c)"
|
||||
|
||||
.PP
|
||||
Get the context (set previously) \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
the context
|
||||
.RE
|
||||
.PP
|
||||
\fBSee also:\fP
|
||||
.RS 4
|
||||
\fBqb_ipcs_context_set()\fP
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_ipcs_context_set\fP (\fBqb_ipcs_connection_t\fP *c, void *context)"
|
||||
|
||||
.PP
|
||||
Associate a 'user' pointer with this connection\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIcontext\fP the point to associate with this connection\&.
|
||||
.br
|
||||
\fIc\fP connection instance
|
||||
.RE
|
||||
.PP
|
||||
\fBSee also:\fP
|
||||
.RS 4
|
||||
\fBqb_ipcs_context_get()\fP
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "\fBqb_ipcs_service_t\fP* \fBqb_ipcs_create\fP (const char *name, int32_tservice_id, enum \fBqb_ipc_type\fPtype, struct \fBqb_ipcs_service_handlers\fP *handlers)"
|
||||
|
||||
.PP
|
||||
Create a new IPC server\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIname\fP for clients to connect to\&.
|
||||
.br
|
||||
\fIservice_id\fP an integer to associate with the service
|
||||
.br
|
||||
\fItype\fP transport type\&.
|
||||
.br
|
||||
\fIhandlers\fP callbacks\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
the new service instance\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_ipcs_destroy\fP (\fBqb_ipcs_service_t\fP *s)"
|
||||
|
||||
.PP
|
||||
Destroy the IPC server\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIs\fP service instance to destroy
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_ipcs_disconnect\fP (\fBqb_ipcs_connection_t\fP *c)"
|
||||
|
||||
.PP
|
||||
Disconnect from this client\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "ssize_t \fBqb_ipcs_event_send\fP (\fBqb_ipcs_connection_t\fP *c, const void *data, size_tsize)"
|
||||
|
||||
.PP
|
||||
Send an asyncronous event message to the client\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.br
|
||||
\fIdata\fP the message to send
|
||||
.br
|
||||
\fIsize\fP the size of the message
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
size sent or -errno for errors
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "ssize_t \fBqb_ipcs_event_sendv\fP (\fBqb_ipcs_connection_t\fP *c, const struct iovec *iov, size_tiov_len)"
|
||||
|
||||
.PP
|
||||
Send an asyncronous event message to the client\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.br
|
||||
\fIiov\fP the iovec struct that points to the message to send
|
||||
.br
|
||||
\fIiov_len\fP the number of iovecs\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
size sent or -errno for errors
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_ipcs_poll_handlers_set\fP (\fBqb_ipcs_service_t\fP *s, struct \fBqb_ipcs_poll_handlers\fP *handlers)"
|
||||
|
||||
.PP
|
||||
Set your poll callbacks\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIs\fP service instance
|
||||
.br
|
||||
\fIhandlers\fP the handlers that you want ipcs to use\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_ipcs_ref\fP (\fBqb_ipcs_service_t\fP *s)"
|
||||
|
||||
.PP
|
||||
Increase the reference counter on the service object\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIs\fP service instance
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_ipcs_request_rate_limit\fP (\fBqb_ipcs_service_t\fP *s, enum \fBqb_ipcs_rate_limit\fPrl)"
|
||||
|
||||
.PP
|
||||
Limit the incomming request rate\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIs\fP service instance
|
||||
.br
|
||||
\fIrl\fP the new rate
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "ssize_t \fBqb_ipcs_response_send\fP (\fBqb_ipcs_connection_t\fP *c, const void *data, size_tsize)"
|
||||
|
||||
.PP
|
||||
Send a response to a incomming request\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.br
|
||||
\fIdata\fP the message to send
|
||||
.br
|
||||
\fIsize\fP the size of the message
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
size sent or -errno for errors
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "ssize_t \fBqb_ipcs_response_sendv\fP (\fBqb_ipcs_connection_t\fP *c, const struct iovec *iov, size_tiov_len)"
|
||||
|
||||
.PP
|
||||
Send a response to a incomming request\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIc\fP connection instance
|
||||
.br
|
||||
\fIiov\fP the iovec struct that points to the message to send
|
||||
.br
|
||||
\fIiov_len\fP the number of iovecs\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
size sent or -errno for errors
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_ipcs_run\fP (\fBqb_ipcs_service_t\fP *s)"
|
||||
|
||||
.PP
|
||||
run the new IPC server\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIs\fP service instance
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
0 == ok; -errno to indicate a failure
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_ipcs_service_id_get\fP (\fBqb_ipcs_connection_t\fP *c)"
|
||||
|
||||
.PP
|
||||
Get the service id related to this connection's service\&. (as passed into \fBqb_ipcs_create()\fP
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
service id\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_ipcs_stats_get\fP (\fBqb_ipcs_service_t\fP *pt, struct \fBqb_ipcs_stats\fP *stats, int32_tclear_after_read)"
|
||||
|
||||
.PP
|
||||
Get the service statistics\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIstats\fP (out) the statistics structure
|
||||
.br
|
||||
\fIclear_after_read\fP clear stats after copying them into stats
|
||||
.br
|
||||
\fIpt\fP service instance
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
0 == ok; -errno to indicate a failure
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_ipcs_unref\fP (\fBqb_ipcs_service_t\fP *s)"
|
||||
|
||||
.PP
|
||||
Decrease the reference counter on the service object\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIs\fP service instance
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SH "Author"
|
||||
.PP
|
||||
Generated automatically by Doxygen for libqb from the source code\&.
|
||||
369
docs/man3/qblist.h.3
Normal file
369
docs/man3/qblist.h.3
Normal file
@ -0,0 +1,369 @@
|
||||
.TH "qblist.h" 3 "Sun Mar 11 2012" "Version 0.11.1" "libqb" \" -*- nroff -*-
|
||||
.ad l
|
||||
.nh
|
||||
.SH NAME
|
||||
qblist.h \-
|
||||
.PP
|
||||
This is a kernel style list implementation\&.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
.PP
|
||||
\fC#include <stdint\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbdefs\&.h>\fP
|
||||
.br
|
||||
|
||||
.SS "Data Structures"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_list_head\fP"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Defines"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_LIST_DECLARE\fP(name) struct \fBqb_list_head\fP name = { &(name), &(name) }"
|
||||
.br
|
||||
.RI "\fIDeclare and initialize a list head\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_INIT_LIST_HEAD\fP(ptr)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_list_entry\fP(ptr, type, member) ((type *)((char *)(ptr)-(char*)(&((type *)0)->member)))"
|
||||
.br
|
||||
.RI "\fIGet the struct for this entry\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_list_for_each\fP(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next)"
|
||||
.br
|
||||
.RI "\fIIterate over a list\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_list_for_each_reverse\fP(pos, head) for (pos = (head)->prev; pos != (head); pos = pos->prev)"
|
||||
.br
|
||||
.RI "\fIIterate over a list backwards\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_list_for_each_safe\fP(pos, n, head)"
|
||||
.br
|
||||
.RI "\fIIterate over a list safe against removal of list entry\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_list_for_each_entry\fP(pos, head, member)"
|
||||
.br
|
||||
.RI "\fIIterate over list of given type\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_list_for_each_entry_reverse\fP(pos, head, member)"
|
||||
.br
|
||||
.RI "\fIIterate backwards over list of given type\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_list_for_each_entry_safe\fP(pos, n, head, member)"
|
||||
.br
|
||||
.RI "\fIIterate over list of given type safe against removal of list entry\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_list_for_each_entry_safe_reverse\fP(pos, n, head, member)"
|
||||
.br
|
||||
.RI "\fIIterate backwards over list safe against removal\&. \fP"
|
||||
.in -1c
|
||||
.SS "Functions"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "static void \fBqb_list_init\fP (struct \fBqb_list_head\fP *head)"
|
||||
.br
|
||||
.RI "\fIInitialize the list entry\&. \fP"
|
||||
.ti -1c
|
||||
.RI "static void \fBqb_list_add\fP (struct \fBqb_list_head\fP *element, struct \fBqb_list_head\fP *head)"
|
||||
.br
|
||||
.RI "\fIAdd this element to the list\&. \fP"
|
||||
.ti -1c
|
||||
.RI "static void \fBqb_list_add_tail\fP (struct \fBqb_list_head\fP *element, struct \fBqb_list_head\fP *head)"
|
||||
.br
|
||||
.RI "\fIAdd to the list (but at the end of the list)\&. \fP"
|
||||
.ti -1c
|
||||
.RI "static void \fBqb_list_del\fP (struct \fBqb_list_head\fP *_remove)"
|
||||
.br
|
||||
.RI "\fIDelete an entry from the list\&. \fP"
|
||||
.ti -1c
|
||||
.RI "static int32_t \fBqb_list_empty\fP (const struct \fBqb_list_head\fP *head)"
|
||||
.br
|
||||
.RI "\fIA quick test to see if the list is empty (pointing to it's self)\&. \fP"
|
||||
.ti -1c
|
||||
.RI "static void \fBqb_list_splice\fP (struct \fBqb_list_head\fP *list, struct \fBqb_list_head\fP *head)"
|
||||
.br
|
||||
.RI "\fIJoin two lists\&. \fP"
|
||||
.ti -1c
|
||||
.RI "static int32_t \fBqb_list_length\fP (struct \fBqb_list_head\fP *head)"
|
||||
.br
|
||||
.RI "\fICount the number of items in the list\&. \fP"
|
||||
.in -1c
|
||||
.SH "Detailed Description"
|
||||
.PP
|
||||
This is a kernel style list implementation\&.
|
||||
|
||||
\fBAuthor:\fP
|
||||
.RS 4
|
||||
Steven Dake sdake@redhat.com
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SH "Define Documentation"
|
||||
.PP
|
||||
.SS "#define \fBQB_INIT_LIST_HEAD\fP(ptr)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
.fi
|
||||
.SS "#define \fBQB_LIST_DECLARE\fP(name) struct \fBqb_list_head\fP name = { &(name), &(name) }"
|
||||
|
||||
.PP
|
||||
Declare and initialize a list head\&.
|
||||
.SS "#define \fBqb_list_entry\fP(ptr, type, member) ((type *)((char *)(ptr)-(char*)(&((type *)0)->member)))"
|
||||
|
||||
.PP
|
||||
Get the struct for this entry\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIptr,:\fP the &struct list_head pointer\&.
|
||||
.br
|
||||
\fItype,:\fP the type of the struct this is embedded in\&.
|
||||
.br
|
||||
\fImember,:\fP the name of the list_struct within the struct\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "#define \fBqb_list_for_each\fP(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next)"
|
||||
|
||||
.PP
|
||||
Iterate over a list\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpos,:\fP the &struct list_head to use as a loop counter\&.
|
||||
.br
|
||||
\fIhead,:\fP the head for your list\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.PP
|
||||
Referenced by qb_list_length()\&.
|
||||
.SS "#define \fBqb_list_for_each_entry\fP(pos, head, member)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
for (pos = qb_list_entry((head)->next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = qb_list_entry(pos->member\&.next, typeof(*pos), member))
|
||||
.fi
|
||||
.PP
|
||||
Iterate over list of given type\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpos,:\fP the type * to use as a loop counter\&.
|
||||
.br
|
||||
\fIhead,:\fP the head for your list\&.
|
||||
.br
|
||||
\fImember,:\fP the name of the list_struct within the struct\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "#define \fBqb_list_for_each_entry_reverse\fP(pos, head, member)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
for (pos = qb_list_entry((head)->prev, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = qb_list_entry(pos->member\&.prev, typeof(*pos), member))
|
||||
.fi
|
||||
.PP
|
||||
Iterate backwards over list of given type\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpos,:\fP the type to use as a loop counter\&.
|
||||
.br
|
||||
\fIhead,:\fP the head for your list\&.
|
||||
.br
|
||||
\fImember,:\fP the name of the list_struct within the struct\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "#define \fBqb_list_for_each_entry_safe\fP(pos, n, head, member)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
for (pos = qb_list_entry((head)->next, typeof(*pos), member), \
|
||||
n = qb_list_entry(pos->member\&.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = qb_list_entry(n->member\&.next, typeof(*n), member))
|
||||
.fi
|
||||
.PP
|
||||
Iterate over list of given type safe against removal of list entry\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpos,:\fP the type * to use as a loop cursor\&.
|
||||
.br
|
||||
\fIn,:\fP another type * to use as temporary storage
|
||||
.br
|
||||
\fIhead,:\fP the head for your list\&.
|
||||
.br
|
||||
\fImember,:\fP the name of the list_struct within the struct\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "#define \fBqb_list_for_each_entry_safe_reverse\fP(pos, n, head, member)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
for (pos = qb_list_entry((head)->prev, typeof(*pos), member), \
|
||||
n = qb_list_entry(pos->member\&.prev, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = qb_list_entry(n->member\&.prev, typeof(*n), member))
|
||||
.fi
|
||||
.PP
|
||||
Iterate backwards over list safe against removal\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpos,:\fP the type * to use as a loop cursor\&.
|
||||
.br
|
||||
\fIn,:\fP another type * to use as temporary storage
|
||||
.br
|
||||
\fIhead,:\fP the head for your list\&.
|
||||
.br
|
||||
\fImember,:\fP the name of the list_struct within the struct\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "#define \fBqb_list_for_each_reverse\fP(pos, head) for (pos = (head)->prev; pos != (head); pos = pos->prev)"
|
||||
|
||||
.PP
|
||||
Iterate over a list backwards\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpos,:\fP the &struct list_head to use as a loop counter\&.
|
||||
.br
|
||||
\fIhead,:\fP the head for your list\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "#define \fBqb_list_for_each_safe\fP(pos, n, head)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
.fi
|
||||
.PP
|
||||
Iterate over a list safe against removal of list entry\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpos,:\fP the &struct list_head to use as a loop counter\&.
|
||||
.br
|
||||
\fIn,:\fP another &struct list_head to use as temporary storage
|
||||
.br
|
||||
\fIhead,:\fP the head for your list\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SH "Function Documentation"
|
||||
.PP
|
||||
.SS "static void \fBqb_list_add\fP (struct \fBqb_list_head\fP *element, struct \fBqb_list_head\fP *head)\fC [inline, static]\fP"
|
||||
|
||||
.PP
|
||||
Add this element to the list\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIelement\fP the new element to insert\&.
|
||||
.br
|
||||
\fIhead\fP pointer to the list head
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.PP
|
||||
References qb_list_head::next, and qb_list_head::prev\&.
|
||||
.SS "static void \fBqb_list_add_tail\fP (struct \fBqb_list_head\fP *element, struct \fBqb_list_head\fP *head)\fC [inline, static]\fP"
|
||||
|
||||
.PP
|
||||
Add to the list (but at the end of the list)\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIelement\fP pointer to the element to add
|
||||
.br
|
||||
\fIhead\fP pointer to the list head
|
||||
.RE
|
||||
.PP
|
||||
\fBSee also:\fP
|
||||
.RS 4
|
||||
\fBqb_list_add()\fP
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.PP
|
||||
References qb_list_head::next, and qb_list_head::prev\&.
|
||||
.SS "static void \fBqb_list_del\fP (struct \fBqb_list_head\fP *_remove)\fC [inline, static]\fP"
|
||||
|
||||
.PP
|
||||
Delete an entry from the list\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fI_remove\fP the list item to remove
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.PP
|
||||
References qb_list_head::next, and qb_list_head::prev\&.
|
||||
.SS "static int32_t \fBqb_list_empty\fP (const struct \fBqb_list_head\fP *head)\fC [inline, static]\fP"
|
||||
|
||||
.PP
|
||||
A quick test to see if the list is empty (pointing to it's self)\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhead\fP pointer to the list head
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
boolean true/false
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.PP
|
||||
References qb_list_head::next\&.
|
||||
.SS "static void \fBqb_list_init\fP (struct \fBqb_list_head\fP *head)\fC [inline, static]\fP"
|
||||
|
||||
.PP
|
||||
Initialize the list entry\&. Points next and prev pointers to head\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhead\fP pointer to the list head
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.PP
|
||||
References qb_list_head::next, and qb_list_head::prev\&.
|
||||
.SS "static int32_t \fBqb_list_length\fP (struct \fBqb_list_head\fP *head)\fC [inline, static]\fP"
|
||||
|
||||
.PP
|
||||
Count the number of items in the list\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIhead,:\fP the head for your list\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
length of the list\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.PP
|
||||
References qb_list_for_each\&.
|
||||
.SS "static void \fBqb_list_splice\fP (struct \fBqb_list_head\fP *list, struct \fBqb_list_head\fP *head)\fC [inline, static]\fP"
|
||||
|
||||
.PP
|
||||
Join two lists\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIlist\fP the new list to add\&.
|
||||
.br
|
||||
\fIhead\fP the place to add it in the first list\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBNote:\fP
|
||||
.RS 4
|
||||
The 'list' is reinitialised
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.PP
|
||||
References qb_list_head::next, and qb_list_head::prev\&.
|
||||
.SH "Author"
|
||||
.PP
|
||||
Generated automatically by Doxygen for libqb from the source code\&.
|
||||
918
docs/man3/qblog.h.3
Normal file
918
docs/man3/qblog.h.3
Normal file
@ -0,0 +1,918 @@
|
||||
.TH "qblog.h" 3 "Sun Mar 11 2012" "Version 0.11.1" "libqb" \" -*- nroff -*-
|
||||
.ad l
|
||||
.nh
|
||||
.SH NAME
|
||||
qblog.h \-
|
||||
.PP
|
||||
The logging API provides four main parts (basics, filtering, threading & blackbox)\&.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
.PP
|
||||
\fC#include <stdint\&.h>\fP
|
||||
.br
|
||||
\fC#include <stdlib\&.h>\fP
|
||||
.br
|
||||
\fC#include <stdio\&.h>\fP
|
||||
.br
|
||||
\fC#include <stdarg\&.h>\fP
|
||||
.br
|
||||
\fC#include <errno\&.h>\fP
|
||||
.br
|
||||
\fC#include <syslog\&.h>\fP
|
||||
.br
|
||||
\fC#include <string\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbutil\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbconfig\&.h>\fP
|
||||
.br
|
||||
|
||||
.SS "Data Structures"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_log_callsite\fP"
|
||||
.br
|
||||
.RI "\fIAn instance of this structure is created in a special ELF section at every dynamic debug callsite\&. \fP"
|
||||
.in -1c
|
||||
.SS "Defines"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "#define \fBLOG_TRACE\fP (LOG_DEBUG + 1)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_LOG_MAX_LEN\fP 512"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_LOG_STRERROR_MAX_LEN\fP 128"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_LOG_INIT_DATA\fP(name)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_LOG_TAG_LIBQB_MSG_BIT\fP 31"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_LOG_TAG_LIBQB_MSG\fP (1 << \fBQB_LOG_TAG_LIBQB_MSG_BIT\fP)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_logt\fP(\fBpriority\fP, \fBtags\fP, fmt, args\&.\&.\&.)"
|
||||
.br
|
||||
.RI "\fIThis is the function to generate a log message if you want to manually add tags\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_log\fP(\fBpriority\fP, fmt, args\&.\&.\&.) \fBqb_logt\fP(\fBpriority\fP, 0, fmt, ##args)"
|
||||
.br
|
||||
.RI "\fIThis is the main function to generate a log message\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_perror\fP(\fBpriority\fP, fmt, args\&.\&.\&.)"
|
||||
.br
|
||||
.RI "\fIThis is similar to perror except it goes into the logging system\&. \fP"
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_enter\fP() \fBqb_log\fP(\fBLOG_TRACE\fP, 'ENTERING %s()', __func__)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBqb_leave\fP() \fBqb_log\fP(\fBLOG_TRACE\fP, 'LEAVING %s()', __func__)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_LOG_SYSLOG\fP 0"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_LOG_STDERR\fP 1"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_LOG_BLACKBOX\fP 2"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_LOG_STDOUT\fP 3"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_LOG_TARGET_MAX\fP 32"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Typedefs"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "typedef const char *(* \fBqb_log_tags_stringify_fn\fP )(uint32_t \fBtags\fP)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_log_filter_fn\fP )(struct \fBqb_log_callsite\fP *cs)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_log_logger_fn\fP )(int32_t t, struct \fBqb_log_callsite\fP *cs, time_t timestamp, const char *msg)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_log_vlogger_fn\fP )(int32_t t, struct \fBqb_log_callsite\fP *cs, time_t timestamp, va_list ap)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_log_close_fn\fP )(int32_t t)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_log_reload_fn\fP )(int32_t t)"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Enumerations"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "enum \fBqb_log_target_state\fP { \fBQB_LOG_STATE_UNUSED\fP = 1, \fBQB_LOG_STATE_DISABLED\fP = 2, \fBQB_LOG_STATE_ENABLED\fP = 3 }"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "enum \fBqb_log_conf\fP { \fBQB_LOG_CONF_ENABLED\fP, \fBQB_LOG_CONF_FACILITY\fP, \fBQB_LOG_CONF_DEBUG\fP, \fBQB_LOG_CONF_SIZE\fP, \fBQB_LOG_CONF_THREADED\fP, \fBQB_LOG_CONF_PRIORITY_BUMP\fP, \fBQB_LOG_CONF_STATE_GET\fP }"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "enum \fBqb_log_filter_type\fP { \fBQB_LOG_FILTER_FILE\fP, \fBQB_LOG_FILTER_FUNCTION\fP, \fBQB_LOG_FILTER_FORMAT\fP }"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "enum \fBqb_log_filter_conf\fP { \fBQB_LOG_FILTER_ADD\fP, \fBQB_LOG_FILTER_REMOVE\fP, \fBQB_LOG_FILTER_CLEAR_ALL\fP, \fBQB_LOG_TAG_SET\fP, \fBQB_LOG_TAG_CLEAR\fP, \fBQB_LOG_TAG_CLEAR_ALL\fP }"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Functions"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_log_callsite\fP \fB__attribute__\fP ((aligned(8)))"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_real_\fP (struct \fBqb_log_callsite\fP *cs,\&.\&.\&.)"
|
||||
.br
|
||||
.RI "\fIInternal function: use \fBqb_log()\fP or \fBqb_logt()\fP \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_real_va_\fP (struct \fBqb_log_callsite\fP *cs, va_list ap)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_from_external_source\fP (const char *\fBfunction\fP, const char *\fBfilename\fP, const char *\fBformat\fP, uint8_t \fBpriority\fP, uint32_t \fBlineno\fP, uint32_t \fBtags\fP,\&.\&.\&.)"
|
||||
.br
|
||||
.RI "\fIThis function is to import logs from other code (like libraries) that provide a callback with their logs\&. \fP"
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_log_callsite\fP * \fBqb_log_callsite_get\fP (const char *\fBfunction\fP, const char *\fBfilename\fP, const char *\fBformat\fP, uint8_t \fBpriority\fP, uint32_t \fBlineno\fP, uint32_t \fBtags\fP)"
|
||||
.br
|
||||
.RI "\fIGet or create a callsite at the give position\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_from_external_source_va\fP (const char *\fBfunction\fP, const char *\fBfilename\fP, const char *\fBformat\fP, uint8_t \fBpriority\fP, uint32_t \fBlineno\fP, uint32_t \fBtags\fP, va_list ap)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_init\fP (const char *name, int32_t facility, uint8_t \fBpriority\fP)"
|
||||
.br
|
||||
.RI "\fIInit the logging system\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_fini\fP (void)"
|
||||
.br
|
||||
.RI "\fILogging system finalization function\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_log_callsites_register\fP (struct \fBqb_log_callsite\fP *_start, struct \fBqb_log_callsite\fP *_stop)"
|
||||
.br
|
||||
.RI "\fIIf you are using dynamically loadable modules via dlopen() and you load them after \fBqb_log_init()\fP then after you load the module you will need to do the following to get the filters to work in that module\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_callsites_dump\fP (void)"
|
||||
.br
|
||||
.RI "\fIDump the callsite info to stdout\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_log_ctl\fP (int32_t target, enum \fBqb_log_conf\fP conf_type, int32_t arg)"
|
||||
.br
|
||||
.RI "\fIMain logging control function\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_log_filter_ctl\fP (int32_t value, enum \fBqb_log_filter_conf\fP c, enum \fBqb_log_filter_type\fP type, const char *text, uint8_t low_priority)"
|
||||
.br
|
||||
.RI "\fIThis allows you modify the 'tags' and 'targets' callsite fields at runtime\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_log_filter_ctl2\fP (int32_t value, enum \fBqb_log_filter_conf\fP c, enum \fBqb_log_filter_type\fP type, const char *text, uint8_t high_priority, uint8_t low_priority)"
|
||||
.br
|
||||
.RI "\fIThis extends \fBqb_log_filter_ctl()\fP by been able to provide a high_priority\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_log_filter_fn_set\fP (\fBqb_log_filter_fn\fP fn)"
|
||||
.br
|
||||
.RI "\fIInstead of using the \fBqb_log_filter_ctl()\fP functions you can apply the filters manually by defining a callback and setting the targets field using \fBqb_bit_set()\fP and \fBqb_bit_clear()\fP like the following below\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_tags_stringify_fn_set\fP (\fBqb_log_tags_stringify_fn\fP fn)"
|
||||
.br
|
||||
.RI "\fISet the callback to map the 'tags' bit map to a string\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_format_set\fP (int32_t t, const char *\fBformat\fP)"
|
||||
.br
|
||||
.RI "\fISet the format specifiers\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_log_file_open\fP (const char *\fBfilename\fP)"
|
||||
.br
|
||||
.RI "\fIOpen a log file\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_file_close\fP (int32_t t)"
|
||||
.br
|
||||
.RI "\fIClose a log file and release is resources\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_log_thread_priority_set\fP (int32_t policy, int32_t \fBpriority\fP)"
|
||||
.br
|
||||
.RI "\fIWhen using threaded logging set the pthread policy and priority\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_log_thread_start\fP (void)"
|
||||
.br
|
||||
.RI "\fIStart the logging pthread\&. \fP"
|
||||
.ti -1c
|
||||
.RI "ssize_t \fBqb_log_blackbox_write_to_file\fP (const char *\fBfilename\fP)"
|
||||
.br
|
||||
.RI "\fIWrite the blackbox to file\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_blackbox_print_from_file\fP (const char *\fBfilename\fP)"
|
||||
.br
|
||||
.RI "\fIRead the blackbox for file and print it out\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_log_custom_open\fP (\fBqb_log_logger_fn\fP log_fn, \fBqb_log_close_fn\fP close_fn, \fBqb_log_reload_fn\fP reload_fn, void *user_data)"
|
||||
.br
|
||||
.RI "\fIOpen a custom log target\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_custom_close\fP (int32_t t)"
|
||||
.br
|
||||
.RI "\fIClose a custom log target and release is resources\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void * \fBqb_log_target_user_data_get\fP (int32_t t)"
|
||||
.br
|
||||
.RI "\fIRetrieve the user data set by either qb_log_custom_open or qb_log_target_user_data_set\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_log_target_user_data_set\fP (int32_t t, void *user_data)"
|
||||
.br
|
||||
.RI "\fIAssociate user data with this log target\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_log_target_format\fP (int32_t target, struct \fBqb_log_callsite\fP *cs, time_t timestamp, const char *formatted_message, char *output_buffer)"
|
||||
.br
|
||||
.RI "\fIformat the callsite and timestamp info according to the format set using \fBqb_log_format_set()\fP It is intended to be used from your custom logger function\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_log_facility2int\fP (const char *fname)"
|
||||
.br
|
||||
.RI "\fIConvert string 'auth' to equivalent number 'LOG_AUTH' etc\&. \fP"
|
||||
.ti -1c
|
||||
.RI "const char * \fBqb_log_facility2str\fP (int32_t fnum)"
|
||||
.br
|
||||
.RI "\fIConvert number 'LOG_AUTH' to equivalent string 'auth' etc\&. \fP"
|
||||
.in -1c
|
||||
.SS "Variables"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "const char * \fBfunction\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "const char * \fBfilename\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "const char * \fBformat\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "uint8_t \fBpriority\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "uint32_t \fBlineno\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "uint32_t \fBtargets\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "uint32_t \fBtags\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_log_callsite\fP \fB__start___verbose\fP []"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "struct \fBqb_log_callsite\fP \fB__stop___verbose\fP []"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "enum \fBqb_log_target_state\fP \fB__attribute__\fP"
|
||||
.br
|
||||
.in -1c
|
||||
.SH "Detailed Description"
|
||||
.PP
|
||||
The logging API provides four main parts (basics, filtering, threading & blackbox)\&.
|
||||
|
||||
The idea behind this logging system is not to be prescriptive but to provide a set of tools to help the developer achieve what they want quickly and easily\&.
|
||||
.PP
|
||||
\fBBasic logging API\&.\fP
|
||||
.RS 4
|
||||
Call \fBqb_log()\fP to generate a log message\&. Then to write the message somewhere meaningful call \fBqb_log_ctl()\fP to configure the targets\&.
|
||||
.RE
|
||||
.PP
|
||||
Simplist possible use:
|
||||
.PP
|
||||
.nf
|
||||
main() {
|
||||
qb_log_init('simple-log', LOG_DAEMON, LOG_INFO);
|
||||
// \&.\&.\&.
|
||||
qb_log(LOG_WARNING, 'watch out');
|
||||
// \&.\&.\&.
|
||||
qb_log_fini();
|
||||
}
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
\fBConfiguring log targets\&.\fP
|
||||
.RS 4
|
||||
A log target can by syslog, stderr, the blackbox or a text file\&. By default only syslog is enabled\&.
|
||||
.RE
|
||||
.PP
|
||||
To enable a target do the following
|
||||
.PP
|
||||
.nf
|
||||
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
syslog, stderr and the blackbox are static (they don't need to be created, just enabled or disabled\&. However you can open multiple logfiles (32 - QB_LOG_BLACKBOX)\&. To do this use the following code\&.
|
||||
.PP
|
||||
.nf
|
||||
mytarget = qb_log_file_open('/var/log/mylogfile');
|
||||
qb_log_ctl(mytarget, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
Once your targets are enabled/opened you can configure them as follows: Configure the size of blackbox
|
||||
.PP
|
||||
.nf
|
||||
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024*10);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
Make logging to file threaded:
|
||||
.PP
|
||||
.nf
|
||||
qb_log_ctl(mytarget, QB_LOG_CONF_THREADED, QB_TRUE);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
To workaround your syslog daemon filtering all messages > LOG_INFO
|
||||
.PP
|
||||
.nf
|
||||
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_PRIORITY_BUMP,
|
||||
LOG_INFO - LOG_DEBUG);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
\fBFiltering messages\&.\fP
|
||||
.RS 4
|
||||
To have more power over what log messages go to which target you can apply filters to the targets\&. What happens is the desired callsites have the correct bit set\&. Then when the log message is generated it gets sent to the targets based on which bit is set in the callsite's 'target' bitmap\&. Messages can be filtered based on the:
|
||||
.IP "1." 4
|
||||
filename + priority
|
||||
.IP "2." 4
|
||||
function name + priority
|
||||
.IP "3." 4
|
||||
format string + priority
|
||||
.PP
|
||||
.RE
|
||||
.PP
|
||||
So to make all logs from evil_fnunction() go to stderr do the following:
|
||||
.PP
|
||||
.nf
|
||||
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_FUNCTION, 'evil_fnunction', LOG_TRACE);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
So to make all logs from totem* (with a priority <= LOG_INFO) go to stderr do the following:
|
||||
.PP
|
||||
.nf
|
||||
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_FILE, 'totem', LOG_INFO);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
So to make all logs with the substring 'ringbuffer' go to stderr do the following:
|
||||
.PP
|
||||
.nf
|
||||
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_FORMAT, 'ringbuffer', LOG_TRACE);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
\fBThreaded logging\&.\fP
|
||||
.RS 4
|
||||
To achieve non-blocking logging you can use threaded logging\&. So any calls to write() or syslog() will not hold up your program\&.
|
||||
.RE
|
||||
.PP
|
||||
Threaded logging use:
|
||||
.PP
|
||||
.nf
|
||||
main() {
|
||||
qb_log_init('simple-log', LOG_DAEMON, LOG_INFO);
|
||||
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_THREADED, QB_TRUE);
|
||||
// \&.\&.\&.
|
||||
daemonize();
|
||||
// call this after you fork()
|
||||
qb_log_thread_start();
|
||||
// \&.\&.\&.
|
||||
qb_log(LOG_WARNING, 'watch out');
|
||||
// \&.\&.\&.
|
||||
qb_log_fini();
|
||||
}
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
\fBA blackbox for in-field diagnosis\&.\fP
|
||||
.RS 4
|
||||
This stores log messages in a ringbuffer so they can be written to file if the program crashes (you will need to catch SIGSEGV)\&. These can then be easily printed out later\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBNote:\fP
|
||||
.RS 4
|
||||
the blackbox is not enabled by default\&.
|
||||
.RE
|
||||
.PP
|
||||
Blackbox usage:
|
||||
.PP
|
||||
.nf
|
||||
static void sigsegv_handler(int sig)
|
||||
{
|
||||
(void)signal (SIGSEGV, SIG_DFL);
|
||||
qb_log_blackbox_write_to_file('simple-log\&.fdata');
|
||||
qb_log_fini();
|
||||
raise(SIGSEGV);
|
||||
}
|
||||
|
||||
main() {
|
||||
|
||||
signal(SIGSEGV, sigsegv_handler);
|
||||
|
||||
qb_log_init('simple-log', LOG_DAEMON, LOG_INFO);
|
||||
qb_log_filter_ctl(QB_LOG_BLACKBOX, QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_FILE, '*', LOG_DEBUG);
|
||||
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024*10);
|
||||
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
// \&.\&.\&.
|
||||
qb_log(LOG_WARNING, 'watch out');
|
||||
// \&.\&.\&.
|
||||
qb_log_fini();
|
||||
}
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
\fBTagging messages\&.\fP
|
||||
.RS 4
|
||||
You can tag messages using the second argument to \fBqb_logt()\fP or by using \fBqb_log_filter_ctl()\fP\&. This can be used to add feature or sub-system information to the logs\&.
|
||||
.RE
|
||||
.PP
|
||||
.PP
|
||||
.nf
|
||||
const char* my_tags_stringify(uint32_t tags) {
|
||||
if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT) {
|
||||
return 'libqb';
|
||||
} else if (tags == 3) {
|
||||
return 'three';
|
||||
} else {
|
||||
return 'MAIN';
|
||||
}
|
||||
}
|
||||
main() {
|
||||
// \&.\&.\&.
|
||||
qb_log_tags_stringify_fn_set(my_tags_stringify);
|
||||
qb_log_format_set(QB_LOG_STDERR, '[%5g] %p %b');
|
||||
// \&.\&.\&.
|
||||
qb_logt(LOG_INFO, 3, 'hello');
|
||||
qb_logt(LOG_INFO, 0, 'hello');
|
||||
}
|
||||
.fi
|
||||
.PP
|
||||
The code above will produce:
|
||||
.PP
|
||||
.nf
|
||||
[libqb] some message
|
||||
[three] info hello
|
||||
[MAIN ] info hello
|
||||
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SH "Define Documentation"
|
||||
.PP
|
||||
.SS "#define \fBLOG_TRACE\fP (LOG_DEBUG + 1)"
|
||||
|
||||
.SS "#define \fBqb_enter\fP() \fBqb_log\fP(\fBLOG_TRACE\fP, 'ENTERING %s()', __func__)"
|
||||
|
||||
.SS "#define \fBqb_leave\fP() \fBqb_log\fP(\fBLOG_TRACE\fP, 'LEAVING %s()', __func__)"
|
||||
|
||||
.SS "#define \fBqb_log\fP(\fBpriority\fP, fmt, args\&.\&.\&.) \fBqb_logt\fP(\fBpriority\fP, 0, fmt, ##args)"
|
||||
|
||||
.PP
|
||||
This is the main function to generate a log message\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpriority\fP this takes syslog priorities\&.
|
||||
.br
|
||||
\fIfmt\fP usual printf style format specifiers
|
||||
.br
|
||||
\fIargs\fP usual printf style args
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "#define \fBQB_LOG_BLACKBOX\fP 2"
|
||||
|
||||
.SS "#define \fBQB_LOG_INIT_DATA\fP(name)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
void name(void); \
|
||||
void name(void) { if (__start___verbose != __stop___verbose) {assert(1);} } \
|
||||
void __attribute__ ((constructor)) name(void);
|
||||
.fi
|
||||
.SS "#define \fBQB_LOG_MAX_LEN\fP 512"
|
||||
|
||||
.SS "#define \fBQB_LOG_STDERR\fP 1"
|
||||
|
||||
.SS "#define \fBQB_LOG_STDOUT\fP 3"
|
||||
|
||||
.SS "#define \fBQB_LOG_STRERROR_MAX_LEN\fP 128"
|
||||
|
||||
.SS "#define \fBQB_LOG_SYSLOG\fP 0"
|
||||
|
||||
.SS "#define \fBQB_LOG_TAG_LIBQB_MSG\fP (1 << \fBQB_LOG_TAG_LIBQB_MSG_BIT\fP)"
|
||||
|
||||
.SS "#define \fBQB_LOG_TAG_LIBQB_MSG_BIT\fP 31"
|
||||
|
||||
.SS "#define \fBQB_LOG_TARGET_MAX\fP 32"
|
||||
|
||||
.SS "#define \fBqb_logt\fP(\fBpriority\fP, \fBtags\fP, fmt, args\&.\&.\&.)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
do { \
|
||||
static struct qb_log_callsite descriptor \
|
||||
__attribute__((section('__verbose'), aligned(8))) = \
|
||||
{ __func__, __FILE__, fmt, priority, __LINE__, 0, tags }; \
|
||||
qb_log_real_(&descriptor, ##args); \
|
||||
} while(0)
|
||||
.fi
|
||||
.PP
|
||||
This is the function to generate a log message if you want to manually add tags\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpriority\fP this takes syslog priorities\&.
|
||||
.br
|
||||
\fItags\fP this is a uint32_t that you can use with \fBqb_log_tags_stringify_fn_set()\fP to 'tag' a log message with a feature or sub-system then you can use '%g' in the format specifer to print it out\&.
|
||||
.br
|
||||
\fIfmt\fP usual printf style format specifiers
|
||||
.br
|
||||
\fIargs\fP usual printf style args
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "#define \fBqb_perror\fP(\fBpriority\fP, fmt, args\&.\&.\&.)"
|
||||
\fBValue:\fP
|
||||
.PP
|
||||
.nf
|
||||
do { \
|
||||
char _perr_buf_[QB_LOG_STRERROR_MAX_LEN]; \
|
||||
const char *_perr_str_ = qb_strerror_r(errno, _perr_buf_, sizeof(_perr_buf_)); \
|
||||
qb_logt(priority, 0, fmt ': %s (%d)', ##args, _perr_str_, errno); \
|
||||
} while(0)
|
||||
.fi
|
||||
.PP
|
||||
This is similar to perror except it goes into the logging system\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIpriority\fP this takes syslog priorities\&.
|
||||
.br
|
||||
\fIfmt\fP usual printf style format specifiers
|
||||
.br
|
||||
\fIargs\fP usual printf style args
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SH "Typedef Documentation"
|
||||
.PP
|
||||
.SS "typedef void(* \fBqb_log_close_fn\fP)(int32_t t)"
|
||||
|
||||
.SS "typedef void(* \fBqb_log_filter_fn\fP)(struct \fBqb_log_callsite\fP *cs)"
|
||||
|
||||
.SS "typedef void(* \fBqb_log_logger_fn\fP)(int32_t t, struct \fBqb_log_callsite\fP *cs, time_t timestamp, const char *msg)"
|
||||
|
||||
.SS "typedef void(* \fBqb_log_reload_fn\fP)(int32_t t)"
|
||||
|
||||
.SS "typedef const char*(* \fBqb_log_tags_stringify_fn\fP)(uint32_t \fBtags\fP)"
|
||||
|
||||
.SS "typedef void(* \fBqb_log_vlogger_fn\fP)(int32_t t, struct \fBqb_log_callsite\fP *cs, time_t timestamp, va_list ap)"
|
||||
|
||||
.SH "Enumeration Type Documentation"
|
||||
.PP
|
||||
.SS "enum \fBqb_log_conf\fP"
|
||||
|
||||
.PP
|
||||
\fBEnumerator: \fP
|
||||
.in +1c
|
||||
.TP
|
||||
\fB\fIQB_LOG_CONF_ENABLED \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_CONF_FACILITY \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_CONF_DEBUG \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_CONF_SIZE \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_CONF_THREADED \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_CONF_PRIORITY_BUMP \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_CONF_STATE_GET \fP\fP
|
||||
|
||||
.SS "enum \fBqb_log_filter_conf\fP"
|
||||
|
||||
.PP
|
||||
\fBEnumerator: \fP
|
||||
.in +1c
|
||||
.TP
|
||||
\fB\fIQB_LOG_FILTER_ADD \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_FILTER_REMOVE \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_FILTER_CLEAR_ALL \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_TAG_SET \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_TAG_CLEAR \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_TAG_CLEAR_ALL \fP\fP
|
||||
|
||||
.SS "enum \fBqb_log_filter_type\fP"
|
||||
|
||||
.PP
|
||||
\fBEnumerator: \fP
|
||||
.in +1c
|
||||
.TP
|
||||
\fB\fIQB_LOG_FILTER_FILE \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_FILTER_FUNCTION \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_FILTER_FORMAT \fP\fP
|
||||
|
||||
.SS "enum \fBqb_log_target_state\fP"
|
||||
|
||||
.PP
|
||||
\fBEnumerator: \fP
|
||||
.in +1c
|
||||
.TP
|
||||
\fB\fIQB_LOG_STATE_UNUSED \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_STATE_DISABLED \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOG_STATE_ENABLED \fP\fP
|
||||
|
||||
.SH "Function Documentation"
|
||||
.PP
|
||||
.SS "struct \fBqb_log_callsite\fP \fB__attribute__\fP ((aligned(8)))"
|
||||
|
||||
.SS "void \fBqb_log_blackbox_print_from_file\fP (const char *filename)"
|
||||
|
||||
.PP
|
||||
Read the blackbox for file and print it out\&.
|
||||
.SS "ssize_t \fBqb_log_blackbox_write_to_file\fP (const char *filename)"
|
||||
|
||||
.PP
|
||||
Write the blackbox to file\&.
|
||||
.SS "struct \fBqb_log_callsite\fP* \fBqb_log_callsite_get\fP (const char *function, const char *filename, const char *format, uint8_tpriority, uint32_tlineno, uint32_ttags)\fC [read]\fP"
|
||||
|
||||
.PP
|
||||
Get or create a callsite at the give position\&. The result can then be passed into \fBqb_log_real_()\fP
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIfunction\fP originating function name
|
||||
.br
|
||||
\fIfilename\fP originating filename
|
||||
.br
|
||||
\fIformat\fP format string
|
||||
.br
|
||||
\fIpriority\fP this takes syslog priorities\&.
|
||||
.br
|
||||
\fIlineno\fP file line number
|
||||
.br
|
||||
\fItags\fP the tag
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_log_callsites_dump\fP (void)"
|
||||
|
||||
.PP
|
||||
Dump the callsite info to stdout\&.
|
||||
.SS "int32_t \fBqb_log_callsites_register\fP (struct \fBqb_log_callsite\fP *_start, struct \fBqb_log_callsite\fP *_stop)"
|
||||
|
||||
.PP
|
||||
If you are using dynamically loadable modules via dlopen() and you load them after \fBqb_log_init()\fP then after you load the module you will need to do the following to get the filters to work in that module\&. .PP
|
||||
.nf
|
||||
_start = dlsym (dl_handle, '__start___verbose');
|
||||
_stop = dlsym (dl_handle, '__stop___verbose');
|
||||
qb_log_callsites_register(_start, _stop);
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_log_ctl\fP (int32_ttarget, enum \fBqb_log_conf\fPconf_type, int32_targ)"
|
||||
|
||||
.PP
|
||||
Main logging control function\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fItarget\fP QB_LOG_SYSLOG, QB_LOG_STDERR or result from \fBqb_log_file_open()\fP
|
||||
.br
|
||||
\fIconf_type\fP what to configure
|
||||
.br
|
||||
\fIarg\fP the new value
|
||||
.RE
|
||||
.PP
|
||||
\fBSee also:\fP
|
||||
.RS 4
|
||||
\fBqb_log_conf\fP
|
||||
.RE
|
||||
.PP
|
||||
\fBReturn values:\fP
|
||||
.RS 4
|
||||
\fI-errno\fP on error
|
||||
.br
|
||||
\fI0\fP on success
|
||||
.br
|
||||
\fIqb_log_target_state\fP for QB_LOG_CONF_STATE_GET
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_log_custom_close\fP (int32_tt)"
|
||||
|
||||
.PP
|
||||
Close a custom log target and release is resources\&.
|
||||
.SS "int32_t \fBqb_log_custom_open\fP (\fBqb_log_logger_fn\fPlog_fn, \fBqb_log_close_fn\fPclose_fn, \fBqb_log_reload_fn\fPreload_fn, void *user_data)"
|
||||
|
||||
.PP
|
||||
Open a custom log target\&. \fBReturn values:\fP
|
||||
.RS 4
|
||||
\fI-errno\fP on error
|
||||
.br
|
||||
\fI3\fP to 31 (to be passed into other qb_log_* functions)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_log_facility2int\fP (const char *fname)"
|
||||
|
||||
.PP
|
||||
Convert string 'auth' to equivalent number 'LOG_AUTH' etc\&.
|
||||
.SS "const char* \fBqb_log_facility2str\fP (int32_tfnum)"
|
||||
|
||||
.PP
|
||||
Convert number 'LOG_AUTH' to equivalent string 'auth' etc\&.
|
||||
.SS "void \fBqb_log_file_close\fP (int32_tt)"
|
||||
|
||||
.PP
|
||||
Close a log file and release is resources\&.
|
||||
.SS "int32_t \fBqb_log_file_open\fP (const char *filename)"
|
||||
|
||||
.PP
|
||||
Open a log file\&. \fBReturn values:\fP
|
||||
.RS 4
|
||||
\fI-errno\fP on error
|
||||
.br
|
||||
\fI3\fP to 31 (to be passed into other qb_log_* functions)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_log_filter_ctl\fP (int32_tvalue, enum \fBqb_log_filter_conf\fPc, enum \fBqb_log_filter_type\fPtype, const char *text, uint8_tlow_priority)"
|
||||
|
||||
.PP
|
||||
This allows you modify the 'tags' and 'targets' callsite fields at runtime\&.
|
||||
.SS "int32_t \fBqb_log_filter_ctl2\fP (int32_tvalue, enum \fBqb_log_filter_conf\fPc, enum \fBqb_log_filter_type\fPtype, const char *text, uint8_thigh_priority, uint8_tlow_priority)"
|
||||
|
||||
.PP
|
||||
This extends \fBqb_log_filter_ctl()\fP by been able to provide a high_priority\&.
|
||||
.SS "int32_t \fBqb_log_filter_fn_set\fP (\fBqb_log_filter_fn\fPfn)"
|
||||
|
||||
.PP
|
||||
Instead of using the \fBqb_log_filter_ctl()\fP functions you can apply the filters manually by defining a callback and setting the targets field using \fBqb_bit_set()\fP and \fBqb_bit_clear()\fP like the following below\&. .PP
|
||||
.nf
|
||||
static void
|
||||
m_filter(struct qb_log_callsite *cs)
|
||||
{
|
||||
if ((cs->priority >= LOG_ALERT &&
|
||||
cs->priority <= LOG_DEBUG) &&
|
||||
strcmp(cs->filename, 'my_c_file\&.c') == 0) {
|
||||
qb_bit_set(cs->targets, QB_LOG_SYSLOG);
|
||||
} else {
|
||||
qb_bit_clear(cs->targets, QB_LOG_SYSLOG);
|
||||
}
|
||||
}
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_log_fini\fP (void)"
|
||||
|
||||
.PP
|
||||
Logging system finalization function\&. It releases any shared memory\&. Stops the logging thread if running\&. Flushes the last message to their destinations\&.
|
||||
.SS "void \fBqb_log_format_set\fP (int32_tt, const char *format)"
|
||||
|
||||
.PP
|
||||
Set the format specifiers\&. n FUNCTION NAME f FILENAME l FILELINE p PRIORITY t TIMESTAMP b BUFFER g TAGS N name (passed into qb_log_init) P PID H hostname
|
||||
.PP
|
||||
any number between % and character specify field length to pad or chop
|
||||
.SS "void \fBqb_log_from_external_source\fP (const char *function, const char *filename, const char *format, uint8_tpriority, uint32_tlineno, uint32_ttags, \&.\&.\&.)"
|
||||
|
||||
.PP
|
||||
This function is to import logs from other code (like libraries) that provide a callback with their logs\&. \fBNote:\fP
|
||||
.RS 4
|
||||
the performance of this will not impress you, as the filtering is done on each log message, not before hand\&. So try doing basic pre-filtering\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIfunction\fP originating function name
|
||||
.br
|
||||
\fIfilename\fP originating filename
|
||||
.br
|
||||
\fIformat\fP format string
|
||||
.br
|
||||
\fIpriority\fP this takes syslog priorities\&.
|
||||
.br
|
||||
\fIlineno\fP file line number
|
||||
.br
|
||||
\fItags\fP this is a uint32_t that you can use with \fBqb_log_tags_stringify_fn_set()\fP to 'tag' a log message with a feature or sub-system then you can use '%g' in the format specifer to print it out\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_log_from_external_source_va\fP (const char *function, const char *filename, const char *format, uint8_tpriority, uint32_tlineno, uint32_ttags, va_listap)"
|
||||
|
||||
.SS "void \fBqb_log_init\fP (const char *name, int32_tfacility, uint8_tpriority)"
|
||||
|
||||
.PP
|
||||
Init the logging system\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIname\fP will be passed into openlog()
|
||||
.br
|
||||
\fIfacility\fP default for all new targets\&.
|
||||
.br
|
||||
\fIpriority\fP a basic filter with this priority will be added\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_log_real_\fP (struct \fBqb_log_callsite\fP *cs, \&.\&.\&.)"
|
||||
|
||||
.PP
|
||||
Internal function: use \fBqb_log()\fP or \fBqb_logt()\fP
|
||||
.SS "void \fBqb_log_real_va_\fP (struct \fBqb_log_callsite\fP *cs, va_listap)"
|
||||
|
||||
.SS "void \fBqb_log_tags_stringify_fn_set\fP (\fBqb_log_tags_stringify_fn\fPfn)"
|
||||
|
||||
.PP
|
||||
Set the callback to map the 'tags' bit map to a string\&.
|
||||
.SS "void \fBqb_log_target_format\fP (int32_ttarget, struct \fBqb_log_callsite\fP *cs, time_ttimestamp, const char *formatted_message, char *output_buffer)"
|
||||
|
||||
.PP
|
||||
format the callsite and timestamp info according to the format set using \fBqb_log_format_set()\fP It is intended to be used from your custom logger function\&.
|
||||
.SS "void* \fBqb_log_target_user_data_get\fP (int32_tt)"
|
||||
|
||||
.PP
|
||||
Retrieve the user data set by either qb_log_custom_open or qb_log_target_user_data_set\&.
|
||||
.SS "int32_t \fBqb_log_target_user_data_set\fP (int32_tt, void *user_data)"
|
||||
|
||||
.PP
|
||||
Associate user data with this log target\&. \fBNote:\fP
|
||||
.RS 4
|
||||
only use this with custom targets
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_log_thread_priority_set\fP (int32_tpolicy, int32_tpriority)"
|
||||
|
||||
.PP
|
||||
When using threaded logging set the pthread policy and priority\&. \fBReturn values:\fP
|
||||
.RS 4
|
||||
\fI-errno\fP on error
|
||||
.br
|
||||
\fI0\fP success
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_log_thread_start\fP (void)"
|
||||
|
||||
.PP
|
||||
Start the logging pthread\&.
|
||||
.SH "Variable Documentation"
|
||||
.PP
|
||||
.SS "enum \fBqb_log_target_state\fP \fB__attribute__\fP"
|
||||
|
||||
.SS "struct \fBqb_log_callsite\fP \fB__start___verbose\fP[]"
|
||||
|
||||
.SS "struct \fBqb_log_callsite\fP \fB__stop___verbose\fP[]"
|
||||
|
||||
.SS "const char* \fBfilename\fP"
|
||||
|
||||
.SS "const char* \fBformat\fP"
|
||||
|
||||
.SS "const char* \fBfunction\fP"
|
||||
|
||||
.SS "uint32_t \fBlineno\fP"
|
||||
|
||||
.SS "uint8_t \fBpriority\fP"
|
||||
|
||||
.SS "uint32_t \fBtags\fP"
|
||||
|
||||
.SS "uint32_t \fBtargets\fP"
|
||||
|
||||
.SH "Author"
|
||||
.PP
|
||||
Generated automatically by Doxygen for libqb from the source code\&.
|
||||
488
docs/man3/qbloop.h.3
Normal file
488
docs/man3/qbloop.h.3
Normal file
@ -0,0 +1,488 @@
|
||||
.TH "qbloop.h" 3 "Sun Mar 11 2012" "Version 0.11.1" "libqb" \" -*- nroff -*-
|
||||
.ad l
|
||||
.nh
|
||||
.SH NAME
|
||||
qbloop.h \-
|
||||
.PP
|
||||
Main loop manages timers, jobs and polling sockets\&.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
.PP
|
||||
\fC#include <signal\&.h>\fP
|
||||
.br
|
||||
\fC#include <stdint\&.h>\fP
|
||||
.br
|
||||
|
||||
.SS "Typedefs"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "typedef struct qb_loop \fBqb_loop_t\fP"
|
||||
.br
|
||||
.RI "\fIAn opaque data type representing the main loop\&. \fP"
|
||||
.ti -1c
|
||||
.RI "typedef uint64_t \fBqb_loop_timer_handle\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef void * \fBqb_loop_signal_handle\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef int32_t(* \fBqb_loop_poll_dispatch_fn\fP )(int32_t fd, int32_t revents, void *data)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_loop_job_dispatch_fn\fP )(void *data)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_loop_timer_dispatch_fn\fP )(void *data)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef int32_t(* \fBqb_loop_signal_dispatch_fn\fP )(int32_t rsignal, void *data)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_loop_poll_low_fds_event_fn\fP )(int32_t not_enough, int32_t fds_available)"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Enumerations"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "enum \fBqb_loop_priority\fP { \fBQB_LOOP_LOW\fP = 0, \fBQB_LOOP_MED\fP = 1, \fBQB_LOOP_HIGH\fP = 2 }"
|
||||
.br
|
||||
.RI "\fIPriorites for jobs, timers & poll\&. \fP"
|
||||
.in -1c
|
||||
.SS "Functions"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "\fBqb_loop_t\fP * \fBqb_loop_create\fP (void)"
|
||||
.br
|
||||
.RI "\fICreate a new main loop\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_loop_destroy\fP (struct qb_loop *l)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "void \fBqb_loop_stop\fP (\fBqb_loop_t\fP *l)"
|
||||
.br
|
||||
.RI "\fIStop the main loop\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_loop_run\fP (\fBqb_loop_t\fP *l)"
|
||||
.br
|
||||
.RI "\fIRun the main loop\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_job_add\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fP p, void *data, \fBqb_loop_job_dispatch_fn\fP dispatch_fn)"
|
||||
.br
|
||||
.RI "\fIAdd a job to the mainloop\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_job_del\fP (struct qb_loop *l, enum \fBqb_loop_priority\fP p, void *data, \fBqb_loop_job_dispatch_fn\fP dispatch_fn)"
|
||||
.br
|
||||
.RI "\fIDelete a job from the mainloop\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_timer_add\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fP p, uint64_t nsec_duration, void *data, \fBqb_loop_timer_dispatch_fn\fP dispatch_fn, \fBqb_loop_timer_handle\fP *timer_handle_out)"
|
||||
.br
|
||||
.RI "\fIAdd a timer to the mainloop\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_timer_del\fP (\fBqb_loop_t\fP *l, \fBqb_loop_timer_handle\fP th)"
|
||||
.br
|
||||
.RI "\fIDelete a timer that is still outstanding\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_timer_is_running\fP (\fBqb_loop_t\fP *l, \fBqb_loop_timer_handle\fP th)"
|
||||
.br
|
||||
.RI "\fICheck to see if a timer that is still outstanding\&. \fP"
|
||||
.ti -1c
|
||||
.RI "uint64_t \fBqb_loop_timer_expire_time_get\fP (struct qb_loop *l, \fBqb_loop_timer_handle\fP th)"
|
||||
.br
|
||||
.RI "\fIGet the time remaining before it expires\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_poll_low_fds_event_set\fP (\fBqb_loop_t\fP *l, \fBqb_loop_poll_low_fds_event_fn\fP fn)"
|
||||
.br
|
||||
.RI "\fISet a callback to receive events on file descriptors getting low\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_poll_add\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fP p, int32_t fd, int32_t events, void *data, \fBqb_loop_poll_dispatch_fn\fP dispatch_fn)"
|
||||
.br
|
||||
.RI "\fIAdd a poll job to the mainloop\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_poll_mod\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fP p, int32_t fd, int32_t events, void *data, \fBqb_loop_poll_dispatch_fn\fP dispatch_fn)"
|
||||
.br
|
||||
.RI "\fIModify a poll job\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_poll_del\fP (\fBqb_loop_t\fP *l, int32_t fd)"
|
||||
.br
|
||||
.RI "\fIDelete a poll job\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_signal_add\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fP p, int32_t signal, void *data, \fBqb_loop_signal_dispatch_fn\fP dispatch_fn, \fBqb_loop_signal_handle\fP *handle)"
|
||||
.br
|
||||
.RI "\fIAdd a signal job\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_signal_mod\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fP p, int32_t signal, void *data, \fBqb_loop_signal_dispatch_fn\fP dispatch_fn, \fBqb_loop_signal_handle\fP handle)"
|
||||
.br
|
||||
.RI "\fIModify the signal job\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_loop_signal_del\fP (\fBqb_loop_t\fP *l, \fBqb_loop_signal_handle\fP handle)"
|
||||
.br
|
||||
.RI "\fIDelete the signal job\&. \fP"
|
||||
.in -1c
|
||||
.SH "Detailed Description"
|
||||
.PP
|
||||
Main loop manages timers, jobs and polling sockets\&.
|
||||
|
||||
|
||||
.SH "Typedef Documentation"
|
||||
.PP
|
||||
.SS "typedef void(* \fBqb_loop_job_dispatch_fn\fP)(void *data)"
|
||||
|
||||
.SS "typedef int32_t(* \fBqb_loop_poll_dispatch_fn\fP)(int32_t fd, int32_t revents, void *data)"
|
||||
|
||||
.SS "typedef void(* \fBqb_loop_poll_low_fds_event_fn\fP)(int32_t not_enough, int32_t fds_available)"
|
||||
|
||||
.SS "typedef int32_t(* \fBqb_loop_signal_dispatch_fn\fP)(int32_t rsignal, void *data)"
|
||||
|
||||
.SS "typedef void* \fBqb_loop_signal_handle\fP"
|
||||
|
||||
.SS "typedef struct qb_loop \fBqb_loop_t\fP"
|
||||
|
||||
.PP
|
||||
An opaque data type representing the main loop\&.
|
||||
.SS "typedef void(* \fBqb_loop_timer_dispatch_fn\fP)(void *data)"
|
||||
|
||||
.SS "typedef uint64_t \fBqb_loop_timer_handle\fP"
|
||||
|
||||
.SH "Enumeration Type Documentation"
|
||||
.PP
|
||||
.SS "enum \fBqb_loop_priority\fP"
|
||||
|
||||
.PP
|
||||
Priorites for jobs, timers & poll\&.
|
||||
.PP
|
||||
\fBEnumerator: \fP
|
||||
.in +1c
|
||||
.TP
|
||||
\fB\fIQB_LOOP_LOW \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOOP_MED \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_LOOP_HIGH \fP\fP
|
||||
|
||||
.SH "Function Documentation"
|
||||
.PP
|
||||
.SS "\fBqb_loop_t\fP* \fBqb_loop_create\fP (void)"
|
||||
|
||||
.PP
|
||||
Create a new main loop\&. \fBReturns:\fP
|
||||
.RS 4
|
||||
loop instance\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_loop_destroy\fP (struct qb_loop *l)"
|
||||
|
||||
.SS "int32_t \fBqb_loop_job_add\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fPp, void *data, \fBqb_loop_job_dispatch_fn\fPdispatch_fn)"
|
||||
|
||||
.PP
|
||||
Add a job to the mainloop\&. This is run in the next cycle of the loop\&.
|
||||
.PP
|
||||
\fBNote:\fP
|
||||
.RS 4
|
||||
it is a one-shot job\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIp\fP the priority
|
||||
.br
|
||||
\fIdata\fP user data passed into the dispatch function
|
||||
.br
|
||||
\fIdispatch_fn\fP callback function
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno == failure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_loop_job_del\fP (struct qb_loop *l, enum \fBqb_loop_priority\fPp, void *data, \fBqb_loop_job_dispatch_fn\fPdispatch_fn)"
|
||||
|
||||
.PP
|
||||
Delete a job from the mainloop\&. This will try to delete the job if it hasn't run yet\&.
|
||||
.PP
|
||||
\fBNote:\fP
|
||||
.RS 4
|
||||
this will remove the first job that matches the paramaters (priority, data, dispatch_fn)\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIp\fP the priority
|
||||
.br
|
||||
\fIdata\fP user data passed into the dispatch function
|
||||
.br
|
||||
\fIdispatch_fn\fP callback function
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno == failure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_loop_poll_add\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fPp, int32_tfd, int32_tevents, void *data, \fBqb_loop_poll_dispatch_fn\fPdispatch_fn)"
|
||||
|
||||
.PP
|
||||
Add a poll job to the mainloop\&. \fBNote:\fP
|
||||
.RS 4
|
||||
it is a re-occuring job\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIp\fP the priority
|
||||
.br
|
||||
\fIfd\fP file descriptor\&.
|
||||
.br
|
||||
\fIevents\fP (POLLIN|POLLOUT) etc \&.\&.\&.\&.
|
||||
.br
|
||||
\fIdata\fP user data passed into the dispatch function
|
||||
.br
|
||||
\fIdispatch_fn\fP callback function
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno == failure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_loop_poll_del\fP (\fBqb_loop_t\fP *l, int32_tfd)"
|
||||
|
||||
.PP
|
||||
Delete a poll job\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIfd\fP file descriptor\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno == failure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_loop_poll_low_fds_event_set\fP (\fBqb_loop_t\fP *l, \fBqb_loop_poll_low_fds_event_fn\fPfn)"
|
||||
|
||||
.PP
|
||||
Set a callback to receive events on file descriptors getting low\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIfn\fP callback function\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno == failure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_loop_poll_mod\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fPp, int32_tfd, int32_tevents, void *data, \fBqb_loop_poll_dispatch_fn\fPdispatch_fn)"
|
||||
|
||||
.PP
|
||||
Modify a poll job\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIp\fP the priority
|
||||
.br
|
||||
\fIfd\fP file descriptor\&.
|
||||
.br
|
||||
\fIevents\fP (POLLIN|POLLOUT) etc \&.\&.\&.\&.
|
||||
.br
|
||||
\fIdata\fP user data passed into the dispatch function
|
||||
.br
|
||||
\fIdispatch_fn\fP callback function
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno == failure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_loop_run\fP (\fBqb_loop_t\fP *l)"
|
||||
|
||||
.PP
|
||||
Run the main loop\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_loop_signal_add\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fPp, int32_tsignal, void *data, \fBqb_loop_signal_dispatch_fn\fPdispatch_fn, \fBqb_loop_signal_handle\fP *handle)"
|
||||
|
||||
.PP
|
||||
Add a signal job\&. Get a callback on this signal (not in the context of the signal)\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIp\fP the priority
|
||||
.br
|
||||
\fIsignal\fP (SIGHUP or SIGINT) etc \&.\&.\&.\&.
|
||||
.br
|
||||
\fIdata\fP user data passed into the dispatch function
|
||||
.br
|
||||
\fIdispatch_fn\fP callback function
|
||||
.br
|
||||
\fIhandle\fP (out) a reference to the signal job
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno == failure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_loop_signal_del\fP (\fBqb_loop_t\fP *l, \fBqb_loop_signal_handle\fPhandle)"
|
||||
|
||||
.PP
|
||||
Delete the signal job\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIhandle\fP (in) a reference to the signal job
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno == failure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_loop_signal_mod\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fPp, int32_tsignal, void *data, \fBqb_loop_signal_dispatch_fn\fPdispatch_fn, \fBqb_loop_signal_handle\fPhandle)"
|
||||
|
||||
.PP
|
||||
Modify the signal job\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIp\fP the priority
|
||||
.br
|
||||
\fIsignal\fP (SIGHUP or SIGINT) etc \&.\&.\&.\&.
|
||||
.br
|
||||
\fIdata\fP user data passed into the dispatch function
|
||||
.br
|
||||
\fIdispatch_fn\fP callback function
|
||||
.br
|
||||
\fIhandle\fP (in) a reference to the signal job
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno == failure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_loop_stop\fP (\fBqb_loop_t\fP *l)"
|
||||
|
||||
.PP
|
||||
Stop the main loop\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_loop_timer_add\fP (\fBqb_loop_t\fP *l, enum \fBqb_loop_priority\fPp, uint64_tnsec_duration, void *data, \fBqb_loop_timer_dispatch_fn\fPdispatch_fn, \fBqb_loop_timer_handle\fP *timer_handle_out)"
|
||||
|
||||
.PP
|
||||
Add a timer to the mainloop\&. \fBNote:\fP
|
||||
.RS 4
|
||||
it is a one-shot job\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIp\fP the priority
|
||||
.br
|
||||
\fInsec_duration\fP nano-secs in the future to run the dispatch\&.
|
||||
.br
|
||||
\fIdata\fP user data passed into the dispatch function
|
||||
.br
|
||||
\fIdispatch_fn\fP callback function
|
||||
.br
|
||||
\fItimer_handle_out\fP handle to delete the timer if needed\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno == failure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_loop_timer_del\fP (\fBqb_loop_t\fP *l, \fBqb_loop_timer_handle\fPth)"
|
||||
|
||||
.PP
|
||||
Delete a timer that is still outstanding\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIth\fP handle to delete the timer if needed\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno == failure)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "uint64_t \fBqb_loop_timer_expire_time_get\fP (struct qb_loop *l, \fBqb_loop_timer_handle\fPth)"
|
||||
|
||||
.PP
|
||||
Get the time remaining before it expires\&. \fBNote:\fP
|
||||
.RS 4
|
||||
if the timer has already expired it will return 0
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIth\fP timer handle\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
nano seconds left
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_loop_timer_is_running\fP (\fBqb_loop_t\fP *l, \fBqb_loop_timer_handle\fPth)"
|
||||
|
||||
.PP
|
||||
Check to see if a timer that is still outstanding\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIl\fP pointer to the loop instance
|
||||
.br
|
||||
\fIth\fP handle to delete the timer if needed\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturn values:\fP
|
||||
.RS 4
|
||||
\fIQB_TRUE\fP yes this timer is outstanding
|
||||
.br
|
||||
\fIQB_FALSE\fP this timer does not exist or has expired
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SH "Author"
|
||||
.PP
|
||||
Generated automatically by Doxygen for libqb from the source code\&.
|
||||
425
docs/man3/qbmap.h.3
Normal file
425
docs/man3/qbmap.h.3
Normal file
@ -0,0 +1,425 @@
|
||||
.TH "qbmap.h" 3 "Sun Mar 11 2012" "Version 0.11.1" "libqb" \" -*- nroff -*-
|
||||
.ad l
|
||||
.nh
|
||||
.SH NAME
|
||||
qbmap.h \-
|
||||
.PP
|
||||
This provides a map interface to a Patricia trie, hashtable or skiplist\&.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
.PP
|
||||
\fC#include <stdint\&.h>\fP
|
||||
.br
|
||||
\fC#include <unistd\&.h>\fP
|
||||
.br
|
||||
|
||||
.SS "Defines"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_MAP_NOTIFY_DELETED\fP 1"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_MAP_NOTIFY_REPLACED\fP 2"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_MAP_NOTIFY_INSERTED\fP 4"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_MAP_NOTIFY_RECURSIVE\fP 8"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_MAP_NOTIFY_FREE\fP 16"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Typedefs"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "typedef struct qb_map \fBqb_map_t\fP"
|
||||
.br
|
||||
.RI "\fIThis is an opaque data type representing an instance of a map\&. \fP"
|
||||
.ti -1c
|
||||
.RI "typedef struct qb_map_iter \fBqb_map_iter_t\fP"
|
||||
.br
|
||||
.RI "\fIThis is an opaque data type representing an iterator instance\&. \fP"
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_map_notify_fn\fP )(uint32_t event, char *key, void *old_value, void *value, void *user_data)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef int32_t(* \fBqb_map_transverse_fn\fP )(const char *key, void *value, void *user_data)"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Functions"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "\fBqb_map_t\fP * \fBqb_hashtable_create\fP (size_t max_size)"
|
||||
.br
|
||||
.RI "\fICreate an unsorted map based on a hashtable\&. \fP"
|
||||
.ti -1c
|
||||
.RI "\fBqb_map_t\fP * \fBqb_skiplist_create\fP (void)"
|
||||
.br
|
||||
.RI "\fICreate a sorted map using a skiplist\&. \fP"
|
||||
.ti -1c
|
||||
.RI "\fBqb_map_t\fP * \fBqb_trie_create\fP (void)"
|
||||
.br
|
||||
.RI "\fICreate a sorted map using a Patricia trie or 'Radix tree'\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_trie_dump\fP (\fBqb_map_t\fP *m)"
|
||||
.br
|
||||
.RI "\fIprint out the nodes in the trie \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_map_notify_add\fP (\fBqb_map_t\fP *m, const char *key, \fBqb_map_notify_fn\fP fn, int32_t events, void *user_data)"
|
||||
.br
|
||||
.RI "\fIAdd a notifier to the map\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_map_notify_del\fP (\fBqb_map_t\fP *m, const char *key, \fBqb_map_notify_fn\fP fn, int32_t events)"
|
||||
.br
|
||||
.RI "\fIDelete a notifier from the map\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_map_notify_del_2\fP (\fBqb_map_t\fP *m, const char *key, \fBqb_map_notify_fn\fP fn, int32_t events, void *user_data)"
|
||||
.br
|
||||
.RI "\fIDelete a notifier from the map (including the userdata)\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_map_put\fP (\fBqb_map_t\fP *map, const char *key, const void *value)"
|
||||
.br
|
||||
.RI "\fIInserts a new key and value into a qb_map_t\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void * \fBqb_map_get\fP (\fBqb_map_t\fP *map, const char *key)"
|
||||
.br
|
||||
.RI "\fIGets the value corresponding to the given key\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_map_rm\fP (\fBqb_map_t\fP *map, const char *key)"
|
||||
.br
|
||||
.RI "\fIRemoves a key/value pair from a map\&. \fP"
|
||||
.ti -1c
|
||||
.RI "size_t \fBqb_map_count_get\fP (\fBqb_map_t\fP *map)"
|
||||
.br
|
||||
.RI "\fIGet the number of items in the map\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_map_foreach\fP (\fBqb_map_t\fP *map, \fBqb_map_transverse_fn\fP func, void *user_data)"
|
||||
.br
|
||||
.RI "\fICalls the given function for each of the key/value pairs in the map\&. \fP"
|
||||
.ti -1c
|
||||
.RI "\fBqb_map_iter_t\fP * \fBqb_map_iter_create\fP (\fBqb_map_t\fP *map)"
|
||||
.br
|
||||
.RI "\fICreate an iterator\&. \fP"
|
||||
.ti -1c
|
||||
.RI "\fBqb_map_iter_t\fP * \fBqb_map_pref_iter_create\fP (\fBqb_map_t\fP *map, const char *prefix)"
|
||||
.br
|
||||
.RI "\fICreate a prefix iterator\&. \fP"
|
||||
.ti -1c
|
||||
.RI "const char * \fBqb_map_iter_next\fP (\fBqb_map_iter_t\fP *i, void **value)"
|
||||
.br
|
||||
.RI "\fIGet the next item\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_map_iter_free\fP (\fBqb_map_iter_t\fP *i)"
|
||||
.br
|
||||
.RI "\fIfree the iterator \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_map_destroy\fP (\fBqb_map_t\fP *map)"
|
||||
.br
|
||||
.RI "\fIDestroy the map, removes all the items from the map\&. \fP"
|
||||
.in -1c
|
||||
.SH "Detailed Description"
|
||||
.PP
|
||||
This provides a map interface to a Patricia trie, hashtable or skiplist\&.
|
||||
|
||||
\fBOrdering\fP
|
||||
.RS 4
|
||||
The hashtable is NOT ordered, but ptrie and skiplist are\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBIterating\fP
|
||||
.RS 4
|
||||
Below is a simple example of how to iterate over a map\&.
|
||||
.PP
|
||||
.nf
|
||||
const char *p;
|
||||
void *data;
|
||||
qb_map_iter_t *it = qb_map_iter_create(m);
|
||||
for (p = qb_map_iter_next(it, &data); p; p = qb_map_iter_next(it, &data)) {
|
||||
printf('%s > %s\n', p, (char*) data);
|
||||
}
|
||||
qb_map_iter_free(it);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.RE
|
||||
.PP
|
||||
Deletion of items within the iterator is supported\&. But note do not free the item memory in the iterator\&. If you need to free the data items then register for a notifier and free the memory there\&. This is required as the items are reference counted\&.
|
||||
.PP
|
||||
.nf
|
||||
qb_map_notify_add(m, NULL, my_map_free_handler,
|
||||
QB_MAP_NOTIFY_FREE, NULL);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
\fBNotifications\fP
|
||||
.RS 4
|
||||
These allow you to get callbacks when values are inserted/removed or replaced\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBNote:\fP
|
||||
.RS 4
|
||||
hashtable only supports deletion and replacement notificatins\&. There is also a special global callback for freeing deleted and replaced values (QB_MAP_NOTIFY_FREE)\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBSee also:\fP
|
||||
.RS 4
|
||||
\fBqb_map_notify_add()\fP \fBqb_map_notify_del_2()\fP
|
||||
.RE
|
||||
.PP
|
||||
\fBPrefix matching\fP
|
||||
.RS 4
|
||||
The ptrie supports prefixes in the iterator:
|
||||
.RE
|
||||
.PP
|
||||
.PP
|
||||
.nf
|
||||
it = qb_map_pref_iter_create(m, 'aa');
|
||||
while ((p = qb_map_iter_next(it, &data)) != NULL) {
|
||||
printf('%s > %s\n', p, (char*)data);
|
||||
}
|
||||
qb_map_iter_free(it);
|
||||
.fi
|
||||
.PP
|
||||
.PP
|
||||
The ptrie also supports prefixes in notifications: (remember to pass QB_MAP_NOTIFY_RECURSIVE into the notify_add\&.
|
||||
.PP
|
||||
.nf
|
||||
qb_map_notify_add(m, 'root', my_map_notification,
|
||||
(QB_MAP_NOTIFY_INSERTED|
|
||||
QB_MAP_NOTIFY_DELETED|
|
||||
QB_MAP_NOTIFY_REPLACED|
|
||||
QB_MAP_NOTIFY_RECURSIVE),
|
||||
NULL);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SH "Define Documentation"
|
||||
.PP
|
||||
.SS "#define \fBQB_MAP_NOTIFY_DELETED\fP 1"
|
||||
|
||||
.SS "#define \fBQB_MAP_NOTIFY_FREE\fP 16"
|
||||
|
||||
.SS "#define \fBQB_MAP_NOTIFY_INSERTED\fP 4"
|
||||
|
||||
.SS "#define \fBQB_MAP_NOTIFY_RECURSIVE\fP 8"
|
||||
|
||||
.SS "#define \fBQB_MAP_NOTIFY_REPLACED\fP 2"
|
||||
|
||||
.SH "Typedef Documentation"
|
||||
.PP
|
||||
.SS "typedef struct qb_map_iter \fBqb_map_iter_t\fP"
|
||||
|
||||
.PP
|
||||
This is an opaque data type representing an iterator instance\&.
|
||||
.SS "typedef void(* \fBqb_map_notify_fn\fP)(uint32_t event, char *key, void *old_value, void *value, void *user_data)"
|
||||
|
||||
.SS "typedef struct qb_map \fBqb_map_t\fP"
|
||||
|
||||
.PP
|
||||
This is an opaque data type representing an instance of a map\&.
|
||||
.SS "typedef int32_t(* \fBqb_map_transverse_fn\fP)(const char *key, void *value, void *user_data)"
|
||||
|
||||
.SH "Function Documentation"
|
||||
.PP
|
||||
.SS "\fBqb_map_t\fP* \fBqb_hashtable_create\fP (size_tmax_size)"
|
||||
|
||||
.PP
|
||||
Create an unsorted map based on a hashtable\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fImax_size\fP maximum size of the hashtable
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
the map instance
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "size_t \fBqb_map_count_get\fP (\fBqb_map_t\fP *map)"
|
||||
|
||||
.PP
|
||||
Get the number of items in the map\&.
|
||||
.SS "void \fBqb_map_destroy\fP (\fBqb_map_t\fP *map)"
|
||||
|
||||
.PP
|
||||
Destroy the map, removes all the items from the map\&.
|
||||
.SS "void \fBqb_map_foreach\fP (\fBqb_map_t\fP *map, \fBqb_map_transverse_fn\fPfunc, void *user_data)"
|
||||
|
||||
.PP
|
||||
Calls the given function for each of the key/value pairs in the map\&. The function is passed the key and value of each pair, and the given data parameter\&. The map is traversed in sorted order\&.
|
||||
.SS "void* \fBqb_map_get\fP (\fBqb_map_t\fP *map, const char *key)"
|
||||
|
||||
.PP
|
||||
Gets the value corresponding to the given key\&. \fBReturn values:\fP
|
||||
.RS 4
|
||||
\fINULL\fP (if the key does not exist)
|
||||
.br
|
||||
\fIa\fP pointer to the value
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "\fBqb_map_iter_t\fP* \fBqb_map_iter_create\fP (\fBqb_map_t\fP *map)"
|
||||
|
||||
.PP
|
||||
Create an iterator\&.
|
||||
.SS "void \fBqb_map_iter_free\fP (\fBqb_map_iter_t\fP *i)"
|
||||
|
||||
.PP
|
||||
free the iterator \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIi\fP the iterator
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "const char* \fBqb_map_iter_next\fP (\fBqb_map_iter_t\fP *i, void **value)"
|
||||
|
||||
.PP
|
||||
Get the next item\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIi\fP the iterator
|
||||
.br
|
||||
\fIvalue\fP (out) the next item's value
|
||||
.RE
|
||||
.PP
|
||||
\fBReturn values:\fP
|
||||
.RS 4
|
||||
\fIthe\fP next key
|
||||
.br
|
||||
\fINULL\fP - the end of the iteration
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_map_notify_add\fP (\fBqb_map_t\fP *m, const char *key, \fBqb_map_notify_fn\fPfn, int32_tevents, void *user_data)"
|
||||
|
||||
.PP
|
||||
Add a notifier to the map\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIm\fP the map instance
|
||||
.br
|
||||
\fIkey\fP the key (or prefix) to attach the notification to\&.
|
||||
.br
|
||||
\fIfn\fP the callback
|
||||
.br
|
||||
\fIevents\fP the type of events to register for\&.
|
||||
.br
|
||||
\fIuser_data\fP a pointer to be passed into the callback
|
||||
.RE
|
||||
.PP
|
||||
\fBNote:\fP
|
||||
.RS 4
|
||||
QB_MAP_NOTIFY_INSERTED is only valid on tries\&.
|
||||
.PP
|
||||
you can use key prefixes with trie maps\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturn values:\fP
|
||||
.RS 4
|
||||
\fI0\fP success
|
||||
.br
|
||||
\fI-errno\fP failure
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_map_notify_del\fP (\fBqb_map_t\fP *m, const char *key, \fBqb_map_notify_fn\fPfn, int32_tevents)"
|
||||
|
||||
.PP
|
||||
Delete a notifier from the map\&. \fBNote:\fP
|
||||
.RS 4
|
||||
the key,fn and events must match those you added\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIm\fP the map instance
|
||||
.br
|
||||
\fIkey\fP the key (or prefix) to attach the notification to\&.
|
||||
.br
|
||||
\fIfn\fP the callback
|
||||
.br
|
||||
\fIevents\fP the type of events to register for\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBReturn values:\fP
|
||||
.RS 4
|
||||
\fI0\fP success
|
||||
.br
|
||||
\fI-errno\fP failure
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_map_notify_del_2\fP (\fBqb_map_t\fP *m, const char *key, \fBqb_map_notify_fn\fPfn, int32_tevents, void *user_data)"
|
||||
|
||||
.PP
|
||||
Delete a notifier from the map (including the userdata)\&. \fBNote:\fP
|
||||
.RS 4
|
||||
the key, fn, events and userdata must match those you added\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIm\fP the map instance
|
||||
.br
|
||||
\fIkey\fP the key (or prefix) to attach the notification to\&.
|
||||
.br
|
||||
\fIfn\fP the callback
|
||||
.br
|
||||
\fIevents\fP the type of events to register for\&.
|
||||
.br
|
||||
\fIuser_data\fP a pointer to be passed into the callback
|
||||
.RE
|
||||
.PP
|
||||
\fBReturn values:\fP
|
||||
.RS 4
|
||||
\fI0\fP success
|
||||
.br
|
||||
\fI-errno\fP failure
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "\fBqb_map_iter_t\fP* \fBqb_map_pref_iter_create\fP (\fBqb_map_t\fP *map, const char *prefix)"
|
||||
|
||||
.PP
|
||||
Create a prefix iterator\&. This will iterate over all items with the given prefix\&.
|
||||
.PP
|
||||
\fBNote:\fP
|
||||
.RS 4
|
||||
this is only supported by the trie\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_map_put\fP (\fBqb_map_t\fP *map, const char *key, const void *value)"
|
||||
|
||||
.PP
|
||||
Inserts a new key and value into a qb_map_t\&. If the key already exists in the qb_map_t, it gets replaced by the new key\&.
|
||||
.SS "int32_t \fBqb_map_rm\fP (\fBqb_map_t\fP *map, const char *key)"
|
||||
|
||||
.PP
|
||||
Removes a key/value pair from a map\&.
|
||||
.SS "\fBqb_map_t\fP* \fBqb_skiplist_create\fP (void)"
|
||||
|
||||
.PP
|
||||
Create a sorted map using a skiplist\&. \fBReturns:\fP
|
||||
.RS 4
|
||||
the map instance
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "\fBqb_map_t\fP* \fBqb_trie_create\fP (void)"
|
||||
|
||||
.PP
|
||||
Create a sorted map using a Patricia trie or 'Radix tree'\&.
|
||||
.SS "void \fBqb_trie_dump\fP (\fBqb_map_t\fP *m)"
|
||||
|
||||
.PP
|
||||
print out the nodes in the trie (for debug purposes)
|
||||
.SH "Author"
|
||||
.PP
|
||||
Generated automatically by Doxygen for libqb from the source code\&.
|
||||
443
docs/man3/qbutil.h.3
Normal file
443
docs/man3/qbutil.h.3
Normal file
@ -0,0 +1,443 @@
|
||||
.TH "qbutil.h" 3 "Sun Mar 11 2012" "Version 0.11.1" "libqb" \" -*- nroff -*-
|
||||
.ad l
|
||||
.nh
|
||||
.SH NAME
|
||||
qbutil.h \-
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
.PP
|
||||
\fC#include <pthread\&.h>\fP
|
||||
.br
|
||||
\fC#include <stdint\&.h>\fP
|
||||
.br
|
||||
\fC#include <unistd\&.h>\fP
|
||||
.br
|
||||
\fC#include <qb/qbdefs\&.h>\fP
|
||||
.br
|
||||
|
||||
.SS "Defines"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "#define \fBQB_UTIL_SW_OVERWRITE\fP 0x01"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Typedefs"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "typedef struct qb_thread_lock_s \fBqb_thread_lock_t\fP"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef void(* \fBqb_util_log_fn_t\fP )(const char *file_name, int32_t file_line, int32_t severity, const char *msg)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "typedef struct qb_util_stopwatch \fBqb_util_stopwatch_t\fP"
|
||||
.br
|
||||
.in -1c
|
||||
.SS "Enumerations"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "enum \fBqb_thread_lock_type_t\fP { \fBQB_THREAD_LOCK_SHORT\fP, \fBQB_THREAD_LOCK_LONG\fP }"
|
||||
.br
|
||||
.RI "\fIQB_THREAD_LOCK_SHORT is a short term lock (spinlock if available on your system) QB_THREAD_LOCK_LONG is a mutex\&. \fP"
|
||||
.in -1c
|
||||
.SS "Functions"
|
||||
|
||||
.in +1c
|
||||
.ti -1c
|
||||
.RI "\fBqb_thread_lock_t\fP * \fBqb_thread_lock_create\fP (\fBqb_thread_lock_type_t\fP type)"
|
||||
.br
|
||||
.RI "\fICreate a new lock of the given type\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_thread_lock\fP (\fBqb_thread_lock_t\fP *tl)"
|
||||
.br
|
||||
.RI "\fICalls either pthread_mutex_lock() or pthread_spin_lock()\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_thread_trylock\fP (\fBqb_thread_lock_t\fP *tl)"
|
||||
.br
|
||||
.RI "\fICalls either pthread_mutex_trylock() or pthread_spin_trylock()\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_thread_unlock\fP (\fBqb_thread_lock_t\fP *tl)"
|
||||
.br
|
||||
.RI "\fICalls either pthread_mutex_unlock() or pthread_spin_unlock\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_thread_lock_destroy\fP (\fBqb_thread_lock_t\fP *tl)"
|
||||
.br
|
||||
.RI "\fICalls either pthread_mutex_destro() or pthread_spin_destroy()\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_util_set_log_function\fP (\fBqb_util_log_fn_t\fP fn) \fBQB_GNUC_DEPRECATED\fP"
|
||||
.br
|
||||
.RI "\fIUse this function to output libqb internal log message as you wish\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_timespec_add_ms\fP (struct timespec *ts, int32_t ms)"
|
||||
.br
|
||||
.RI "\fIAdd milliseconds onto the timespec\&. \fP"
|
||||
.ti -1c
|
||||
.RI "uint64_t \fBqb_util_nano_current_get\fP (void)"
|
||||
.br
|
||||
.RI "\fIGet the current number of nano secounds produced by the systems incrementing clock (CLOCK_MONOTOMIC if available)\&. \fP"
|
||||
.ti -1c
|
||||
.RI "uint64_t \fBqb_util_nano_monotonic_hz\fP (void)"
|
||||
.br
|
||||
.RI "\fIGet the frequence of the clock used in \fBqb_util_nano_current_get()\fP\&. \fP"
|
||||
.ti -1c
|
||||
.RI "uint64_t \fBqb_util_nano_from_epoch_get\fP (void)"
|
||||
.br
|
||||
.RI "\fIGet the time in nano seconds since epoch\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_util_timespec_from_epoch_get\fP (struct timespec *ts)"
|
||||
.br
|
||||
.RI "\fIGet the time in timespec since epoch\&. \fP"
|
||||
.ti -1c
|
||||
.RI "char * \fBqb_strerror_r\fP (int errnum, char *buf, size_t buflen)"
|
||||
.br
|
||||
.RI "\fIstrerror_r replacement\&. \fP"
|
||||
.ti -1c
|
||||
.RI "\fBqb_util_stopwatch_t\fP * \fBqb_util_stopwatch_create\fP (void)"
|
||||
.br
|
||||
.RI "\fICreate a Stopwatch (to time operations) \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_util_stopwatch_free\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
.br
|
||||
.RI "\fIFree the stopwatch\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_util_stopwatch_start\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
.br
|
||||
.RI "\fIStart the stopwatch\&. \fP"
|
||||
.ti -1c
|
||||
.RI "void \fBqb_util_stopwatch_stop\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
.br
|
||||
.RI "\fIStop the stopwatch\&. \fP"
|
||||
.ti -1c
|
||||
.RI "uint64_t \fBqb_util_stopwatch_us_elapsed_get\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
.br
|
||||
.RI "\fIGet the elapsed time in micro seconds\&. \fP"
|
||||
.ti -1c
|
||||
.RI "float \fBqb_util_stopwatch_sec_elapsed_get\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
.br
|
||||
.RI "\fIGet the elapsed time in seconds\&. \fP"
|
||||
.ti -1c
|
||||
.RI "int32_t \fBqb_util_stopwatch_split_ctl\fP (\fBqb_util_stopwatch_t\fP *sw, uint32_t max_splits, uint32_t options)"
|
||||
.br
|
||||
.ti -1c
|
||||
.RI "uint64_t \fBqb_util_stopwatch_split\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
.br
|
||||
.RI "\fICreate a new time split (or lap time) \fP"
|
||||
.ti -1c
|
||||
.RI "uint32_t \fBqb_util_stopwatch_split_last\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
.br
|
||||
.RI "\fIGet the last split index to be used by \fBqb_util_stopwatch_time_split_get()\fP \fP"
|
||||
.ti -1c
|
||||
.RI "uint64_t \fBqb_util_stopwatch_time_split_get\fP (\fBqb_util_stopwatch_t\fP *sw, uint32_t receint, uint32_t older)"
|
||||
.br
|
||||
.RI "\fIRead the time split (in us) from 'receint' to 'older'\&. \fP"
|
||||
.in -1c
|
||||
.SH "Detailed Description"
|
||||
.PP
|
||||
\fBAuthor:\fP
|
||||
.RS 4
|
||||
Angus Salkeld asalkeld@redhat.com
|
||||
.RE
|
||||
.PP
|
||||
These are some convience functions used throughout libqb\&.
|
||||
.PP
|
||||
\fBLocking\fP
|
||||
.RS 4
|
||||
|
||||
.IP "\(bu" 2
|
||||
\fBqb_thread_lock_create()\fP
|
||||
.IP "\(bu" 2
|
||||
\fBqb_thread_lock()\fP
|
||||
.IP "\(bu" 2
|
||||
\fBqb_thread_trylock()\fP
|
||||
.IP "\(bu" 2
|
||||
\fBqb_thread_unlock()\fP
|
||||
.IP "\(bu" 2
|
||||
\fBqb_thread_lock_destroy()\fP
|
||||
.PP
|
||||
.RE
|
||||
.PP
|
||||
\fBTime functions\fP
|
||||
.RS 4
|
||||
|
||||
.IP "\(bu" 2
|
||||
\fBqb_timespec_add_ms()\fP
|
||||
.IP "\(bu" 2
|
||||
\fBqb_util_nano_current_get()\fP
|
||||
.IP "\(bu" 2
|
||||
\fBqb_util_nano_monotonic_hz()\fP
|
||||
.IP "\(bu" 2
|
||||
\fBqb_util_nano_from_epoch_get()\fP
|
||||
.IP "\(bu" 2
|
||||
\fBqb_util_timespec_from_epoch_get()\fP
|
||||
.PP
|
||||
.RE
|
||||
.PP
|
||||
\fBBasic Stopwatch\fP
|
||||
.RS 4
|
||||
|
||||
.PP
|
||||
.nf
|
||||
uint64_t elapsed1;
|
||||
uint64_t elapsed2;
|
||||
qb_util_stopwatch_t *sw = qb_util_stopwatch_create();
|
||||
|
||||
qb_util_stopwatch_start(sw);
|
||||
|
||||
usleep(sometime);
|
||||
qb_util_stopwatch_stop(sw);
|
||||
elapsed1 = qb_util_stopwatch_us_elapsed_get(sw);
|
||||
|
||||
usleep(somemoretime);
|
||||
qb_util_stopwatch_stop(sw);
|
||||
elapsed2 = qb_util_stopwatch_us_elapsed_get(sw);
|
||||
|
||||
qb_util_stopwatch_free(sw);
|
||||
|
||||
.fi
|
||||
.PP
|
||||
.RE
|
||||
.PP
|
||||
\fBStopwatch with splits\fP
|
||||
.RS 4
|
||||
Setup a stopwatch with space for 3 splits\&.
|
||||
.RE
|
||||
.PP
|
||||
.PP
|
||||
.nf
|
||||
uint64_t split;
|
||||
qb_util_stopwatch_t *sw = qb_util_stopwatch_create();
|
||||
|
||||
qb_util_stopwatch_split_ctl(sw, 3, 0);
|
||||
qb_util_stopwatch_start(sw);
|
||||
|
||||
usleep(sometime);
|
||||
qb_util_stopwatch_split(sw);
|
||||
|
||||
usleep(somemoretime);
|
||||
qb_util_stopwatch_split(sw);
|
||||
|
||||
usleep(somemoretime);
|
||||
qb_util_stopwatch_split(sw);
|
||||
|
||||
idx = qb_util_stopwatch_split_last(sw);
|
||||
do {
|
||||
split = qb_util_stopwatch_time_split_get(sw, idx, idx);
|
||||
qb_log(LOG_INFO, 'split %d is %'PRIu64'', last, split);
|
||||
idx--;
|
||||
} while (split > 0);
|
||||
|
||||
split = qb_util_stopwatch_time_split_get(sw, 2, 1);
|
||||
qb_log(LOG_INFO, 'time between second and third split is %'PRIu64'', split);
|
||||
|
||||
qb_util_stopwatch_free(sw);
|
||||
.fi
|
||||
.PP
|
||||
|
||||
.SH "Define Documentation"
|
||||
.PP
|
||||
.SS "#define \fBQB_UTIL_SW_OVERWRITE\fP 0x01"
|
||||
|
||||
.SH "Typedef Documentation"
|
||||
.PP
|
||||
.SS "typedef struct qb_thread_lock_s \fBqb_thread_lock_t\fP"
|
||||
|
||||
.SS "typedef void(* \fBqb_util_log_fn_t\fP)(const char *file_name, int32_t file_line, int32_t severity, const char *msg)"
|
||||
|
||||
.SS "typedef struct qb_util_stopwatch \fBqb_util_stopwatch_t\fP"
|
||||
|
||||
.SH "Enumeration Type Documentation"
|
||||
.PP
|
||||
.SS "enum \fBqb_thread_lock_type_t\fP"
|
||||
|
||||
.PP
|
||||
QB_THREAD_LOCK_SHORT is a short term lock (spinlock if available on your system) QB_THREAD_LOCK_LONG is a mutex\&.
|
||||
.PP
|
||||
\fBEnumerator: \fP
|
||||
.in +1c
|
||||
.TP
|
||||
\fB\fIQB_THREAD_LOCK_SHORT \fP\fP
|
||||
.TP
|
||||
\fB\fIQB_THREAD_LOCK_LONG \fP\fP
|
||||
|
||||
.SH "Function Documentation"
|
||||
.PP
|
||||
.SS "char* \fBqb_strerror_r\fP (interrnum, char *buf, size_tbuflen)"
|
||||
|
||||
.PP
|
||||
strerror_r replacement\&.
|
||||
.SS "int32_t \fBqb_thread_lock\fP (\fBqb_thread_lock_t\fP *tl)"
|
||||
|
||||
.PP
|
||||
Calls either pthread_mutex_lock() or pthread_spin_lock()\&.
|
||||
.SS "\fBqb_thread_lock_t\fP* \fBqb_thread_lock_create\fP (\fBqb_thread_lock_type_t\fPtype)"
|
||||
|
||||
.PP
|
||||
Create a new lock of the given type\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fItype\fP QB_THREAD_LOCK_SHORT == spinlock (where available, else mutex) QB_THREAD_LOCK_LONG == mutex
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
pointer to qb_thread_lock_type_t or NULL on error\&.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_thread_lock_destroy\fP (\fBqb_thread_lock_t\fP *tl)"
|
||||
|
||||
.PP
|
||||
Calls either pthread_mutex_destro() or pthread_spin_destroy()\&.
|
||||
.SS "int32_t \fBqb_thread_trylock\fP (\fBqb_thread_lock_t\fP *tl)"
|
||||
|
||||
.PP
|
||||
Calls either pthread_mutex_trylock() or pthread_spin_trylock()\&.
|
||||
.SS "int32_t \fBqb_thread_unlock\fP (\fBqb_thread_lock_t\fP *tl)"
|
||||
|
||||
.PP
|
||||
Calls either pthread_mutex_unlock() or pthread_spin_unlock\&.
|
||||
.SS "void \fBqb_timespec_add_ms\fP (struct timespec *ts, int32_tms)"
|
||||
|
||||
.PP
|
||||
Add milliseconds onto the timespec\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIts\fP the ts to add to
|
||||
.br
|
||||
\fIms\fP the amount of milliseconds to increment ts
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "uint64_t \fBqb_util_nano_current_get\fP (void)"
|
||||
|
||||
.PP
|
||||
Get the current number of nano secounds produced by the systems incrementing clock (CLOCK_MONOTOMIC if available)\&.
|
||||
.SS "uint64_t \fBqb_util_nano_from_epoch_get\fP (void)"
|
||||
|
||||
.PP
|
||||
Get the time in nano seconds since epoch\&.
|
||||
.SS "uint64_t \fBqb_util_nano_monotonic_hz\fP (void)"
|
||||
|
||||
.PP
|
||||
Get the frequence of the clock used in \fBqb_util_nano_current_get()\fP\&.
|
||||
.SS "void \fBqb_util_set_log_function\fP (\fBqb_util_log_fn_t\fPfn)"
|
||||
|
||||
.PP
|
||||
Use this function to output libqb internal log message as you wish\&.
|
||||
.SS "\fBqb_util_stopwatch_t\fP* \fBqb_util_stopwatch_create\fP (void)"
|
||||
|
||||
.PP
|
||||
Create a Stopwatch (to time operations)
|
||||
.SS "void \fBqb_util_stopwatch_free\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
|
||||
.PP
|
||||
Free the stopwatch\&.
|
||||
.SS "float \fBqb_util_stopwatch_sec_elapsed_get\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
|
||||
.PP
|
||||
Get the elapsed time in seconds\&. (it must have been started and stopped)\&.
|
||||
.SS "uint64_t \fBqb_util_stopwatch_split\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
|
||||
.PP
|
||||
Create a new time split (or lap time) \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIsw\fP the stopwatch
|
||||
.RE
|
||||
.PP
|
||||
\fBReturn values:\fP
|
||||
.RS 4
|
||||
\fIthe\fP relative split time in micro seconds
|
||||
.br
|
||||
\fI0\fP if no more splits available
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "int32_t \fBqb_util_stopwatch_split_ctl\fP (\fBqb_util_stopwatch_t\fP *sw, uint32_tmax_splits, uint32_toptions)"
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIsw\fP the stopwatch
|
||||
.br
|
||||
\fImax_splits\fP maximum number of time splits
|
||||
.br
|
||||
\fIoptions\fP (0 or QB_UTIL_SW_OVERWRITE )
|
||||
.RE
|
||||
.PP
|
||||
\fBReturn values:\fP
|
||||
.RS 4
|
||||
\fI0\fP on success
|
||||
.br
|
||||
\fI-errno\fP on failure
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "uint32_t \fBqb_util_stopwatch_split_last\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
|
||||
.PP
|
||||
Get the last split index to be used by \fBqb_util_stopwatch_time_split_get()\fP \fBNote:\fP
|
||||
.RS 4
|
||||
this is zero based
|
||||
.RE
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIsw\fP the stopwatch
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
the last entry index
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "void \fBqb_util_stopwatch_start\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
|
||||
.PP
|
||||
Start the stopwatch\&. This also acts as a reset\&. Essentially it sets the starting time and clears the splits\&.
|
||||
.SS "void \fBqb_util_stopwatch_stop\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
|
||||
.PP
|
||||
Stop the stopwatch\&. This just allows you to get the elapsed time\&. So you can call this multiple times\&. Do not call \fBqb_util_stopwatch_start()\fP unless you want to reset the stopwatch\&.
|
||||
.SS "uint64_t \fBqb_util_stopwatch_time_split_get\fP (\fBqb_util_stopwatch_t\fP *sw, uint32_treceint, uint32_tolder)"
|
||||
|
||||
.PP
|
||||
Read the time split (in us) from 'receint' to 'older'\&. If older == receint then the cumulated split will be returned (from the stopwatch start)\&.
|
||||
.PP
|
||||
\fBParameters:\fP
|
||||
.RS 4
|
||||
\fIsw\fP the stopwatch
|
||||
.br
|
||||
\fIreceint\fP split
|
||||
.br
|
||||
\fIolder\fP split
|
||||
.RE
|
||||
.PP
|
||||
\fBReturn values:\fP
|
||||
.RS 4
|
||||
\fIthe\fP split time in micro seconds
|
||||
.br
|
||||
\fI0\fP if not a valid split
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SS "uint64_t \fBqb_util_stopwatch_us_elapsed_get\fP (\fBqb_util_stopwatch_t\fP *sw)"
|
||||
|
||||
.PP
|
||||
Get the elapsed time in micro seconds\&. (it must have been started and stopped)\&.
|
||||
.SS "void \fBqb_util_timespec_from_epoch_get\fP (struct timespec *ts)"
|
||||
|
||||
.PP
|
||||
Get the time in timespec since epoch\&. \fBParameters:\fP
|
||||
.RS 4
|
||||
\fIts\fP (out) the timespec
|
||||
.RE
|
||||
.PP
|
||||
\fBReturns:\fP
|
||||
.RS 4
|
||||
status (0 == ok, -errno on error)
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SH "Author"
|
||||
.PP
|
||||
Generated automatically by Doxygen for libqb from the source code\&.
|
||||
51
examples/Makefile.am
Normal file
51
examples/Makefile.am
Normal file
@ -0,0 +1,51 @@
|
||||
# Copyright (c) 2011 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Angus Salkeld <asalkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
MAINTAINERCLEANFILES = Makefiles.in
|
||||
EXTRA_DIST =
|
||||
CLEANFILES =
|
||||
|
||||
noinst_PROGRAMS = mapnotify simplelog tcpclient tcpserver ipcclient ipcserver
|
||||
|
||||
mapnotify_SOURCES = mapnotify.c $(top_builddir)/include/qb/qbmap.h
|
||||
mapnotify_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
mapnotify_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la
|
||||
|
||||
simplelog_SOURCES = simplelog.c $(top_builddir)/include/qb/qblog.h
|
||||
simplelog_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
simplelog_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la
|
||||
|
||||
tcpclient_SOURCES = tcpclient.c $(top_builddir)/include/qb/qbloop.h
|
||||
tcpclient_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
tcpclient_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la
|
||||
|
||||
tcpserver_SOURCES = tcpserver.c $(top_builddir)/include/qb/qbloop.h
|
||||
tcpserver_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
tcpserver_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la
|
||||
|
||||
ipcclient_SOURCES = ipcclient.c $(top_builddir)/include/qb/qbloop.h \
|
||||
$(top_builddir)/include/qb/qbipcc.h
|
||||
ipcclient_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
ipcclient_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la
|
||||
|
||||
ipcserver_SOURCES = ipcserver.c $(top_builddir)/include/qb/qbloop.h \
|
||||
$(top_builddir)/include/qb/qbipcs.h
|
||||
ipcserver_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include \
|
||||
$(GLIB_CFLAGS)
|
||||
ipcserver_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la $(GLIB_LIBS)
|
||||
691
examples/Makefile.in
Normal file
691
examples/Makefile.in
Normal file
@ -0,0 +1,691 @@
|
||||
# Makefile.in generated by automake 1.11.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
noinst_PROGRAMS = mapnotify$(EXEEXT) simplelog$(EXEEXT) \
|
||||
tcpclient$(EXEEXT) tcpserver$(EXEEXT) ipcclient$(EXEEXT) \
|
||||
ipcserver$(EXEEXT)
|
||||
subdir = examples
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/include/config.h \
|
||||
$(top_builddir)/include/qb/qbconfig.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
PROGRAMS = $(noinst_PROGRAMS)
|
||||
am_ipcclient_OBJECTS = ipcclient-ipcclient.$(OBJEXT)
|
||||
ipcclient_OBJECTS = $(am_ipcclient_OBJECTS)
|
||||
am__DEPENDENCIES_1 =
|
||||
ipcclient_DEPENDENCIES = $(am__DEPENDENCIES_1) \
|
||||
$(top_builddir)/lib/libqb.la
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||
am__v_lt_0 = --silent
|
||||
am_ipcserver_OBJECTS = ipcserver-ipcserver.$(OBJEXT)
|
||||
ipcserver_OBJECTS = $(am_ipcserver_OBJECTS)
|
||||
ipcserver_DEPENDENCIES = $(am__DEPENDENCIES_1) \
|
||||
$(top_builddir)/lib/libqb.la $(am__DEPENDENCIES_1)
|
||||
am_mapnotify_OBJECTS = mapnotify-mapnotify.$(OBJEXT)
|
||||
mapnotify_OBJECTS = $(am_mapnotify_OBJECTS)
|
||||
mapnotify_DEPENDENCIES = $(am__DEPENDENCIES_1) \
|
||||
$(top_builddir)/lib/libqb.la
|
||||
am_simplelog_OBJECTS = simplelog-simplelog.$(OBJEXT)
|
||||
simplelog_OBJECTS = $(am_simplelog_OBJECTS)
|
||||
simplelog_DEPENDENCIES = $(am__DEPENDENCIES_1) \
|
||||
$(top_builddir)/lib/libqb.la
|
||||
am_tcpclient_OBJECTS = tcpclient-tcpclient.$(OBJEXT)
|
||||
tcpclient_OBJECTS = $(am_tcpclient_OBJECTS)
|
||||
tcpclient_DEPENDENCIES = $(am__DEPENDENCIES_1) \
|
||||
$(top_builddir)/lib/libqb.la
|
||||
am_tcpserver_OBJECTS = tcpserver-tcpserver.$(OBJEXT)
|
||||
tcpserver_OBJECTS = $(am_tcpserver_OBJECTS)
|
||||
tcpserver_DEPENDENCIES = $(am__DEPENDENCIES_1) \
|
||||
$(top_builddir)/lib/libqb.la
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include -I$(top_builddir)/include/qb
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
|
||||
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||||
$(AM_CFLAGS) $(CFLAGS)
|
||||
AM_V_CC = $(am__v_CC_@AM_V@)
|
||||
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
||||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
SOURCES = $(ipcclient_SOURCES) $(ipcserver_SOURCES) \
|
||||
$(mapnotify_SOURCES) $(simplelog_SOURCES) $(tcpclient_SOURCES) \
|
||||
$(tcpserver_SOURCES)
|
||||
DIST_SOURCES = $(ipcclient_SOURCES) $(ipcserver_SOURCES) \
|
||||
$(mapnotify_SOURCES) $(simplelog_SOURCES) $(tcpclient_SOURCES) \
|
||||
$(tcpserver_SOURCES)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CHECK_CFLAGS = @CHECK_CFLAGS@
|
||||
CHECK_LIBS = @CHECK_LIBS@
|
||||
CP = @CP@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DOXYGEN = @DOXYGEN@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GLIB_CFLAGS = @GLIB_CFLAGS@
|
||||
GLIB_LIBS = @GLIB_LIBS@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIB_RT = @LIB_RT@
|
||||
LINT_FLAGS = @LINT_FLAGS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKGCONFIG = @PKGCONFIG@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
SOCKETDIR = @SOCKETDIR@
|
||||
SPLINT = @SPLINT@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
# Copyright (c) 2011 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Angus Salkeld <asalkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
MAINTAINERCLEANFILES = Makefiles.in
|
||||
EXTRA_DIST =
|
||||
CLEANFILES =
|
||||
mapnotify_SOURCES = mapnotify.c $(top_builddir)/include/qb/qbmap.h
|
||||
mapnotify_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
mapnotify_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la
|
||||
simplelog_SOURCES = simplelog.c $(top_builddir)/include/qb/qblog.h
|
||||
simplelog_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
simplelog_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la
|
||||
tcpclient_SOURCES = tcpclient.c $(top_builddir)/include/qb/qbloop.h
|
||||
tcpclient_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
tcpclient_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la
|
||||
tcpserver_SOURCES = tcpserver.c $(top_builddir)/include/qb/qbloop.h
|
||||
tcpserver_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
tcpserver_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la
|
||||
ipcclient_SOURCES = ipcclient.c $(top_builddir)/include/qb/qbloop.h \
|
||||
$(top_builddir)/include/qb/qbipcc.h
|
||||
|
||||
ipcclient_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
ipcclient_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la
|
||||
ipcserver_SOURCES = ipcserver.c $(top_builddir)/include/qb/qbloop.h \
|
||||
$(top_builddir)/include/qb/qbipcs.h
|
||||
|
||||
ipcserver_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include \
|
||||
$(GLIB_CFLAGS)
|
||||
|
||||
ipcserver_LDADD = $(LIB_RT) $(top_builddir)/lib/libqb.la $(GLIB_LIBS)
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu examples/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu examples/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
clean-noinstPROGRAMS:
|
||||
@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
|
||||
echo " rm -f" $$list; \
|
||||
rm -f $$list || exit $$?; \
|
||||
test -n "$(EXEEXT)" || exit 0; \
|
||||
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
|
||||
echo " rm -f" $$list; \
|
||||
rm -f $$list
|
||||
ipcclient$(EXEEXT): $(ipcclient_OBJECTS) $(ipcclient_DEPENDENCIES) $(EXTRA_ipcclient_DEPENDENCIES)
|
||||
@rm -f ipcclient$(EXEEXT)
|
||||
$(AM_V_CCLD)$(LINK) $(ipcclient_OBJECTS) $(ipcclient_LDADD) $(LIBS)
|
||||
ipcserver$(EXEEXT): $(ipcserver_OBJECTS) $(ipcserver_DEPENDENCIES) $(EXTRA_ipcserver_DEPENDENCIES)
|
||||
@rm -f ipcserver$(EXEEXT)
|
||||
$(AM_V_CCLD)$(LINK) $(ipcserver_OBJECTS) $(ipcserver_LDADD) $(LIBS)
|
||||
mapnotify$(EXEEXT): $(mapnotify_OBJECTS) $(mapnotify_DEPENDENCIES) $(EXTRA_mapnotify_DEPENDENCIES)
|
||||
@rm -f mapnotify$(EXEEXT)
|
||||
$(AM_V_CCLD)$(LINK) $(mapnotify_OBJECTS) $(mapnotify_LDADD) $(LIBS)
|
||||
simplelog$(EXEEXT): $(simplelog_OBJECTS) $(simplelog_DEPENDENCIES) $(EXTRA_simplelog_DEPENDENCIES)
|
||||
@rm -f simplelog$(EXEEXT)
|
||||
$(AM_V_CCLD)$(LINK) $(simplelog_OBJECTS) $(simplelog_LDADD) $(LIBS)
|
||||
tcpclient$(EXEEXT): $(tcpclient_OBJECTS) $(tcpclient_DEPENDENCIES) $(EXTRA_tcpclient_DEPENDENCIES)
|
||||
@rm -f tcpclient$(EXEEXT)
|
||||
$(AM_V_CCLD)$(LINK) $(tcpclient_OBJECTS) $(tcpclient_LDADD) $(LIBS)
|
||||
tcpserver$(EXEEXT): $(tcpserver_OBJECTS) $(tcpserver_DEPENDENCIES) $(EXTRA_tcpserver_DEPENDENCIES)
|
||||
@rm -f tcpserver$(EXEEXT)
|
||||
$(AM_V_CCLD)$(LINK) $(tcpserver_OBJECTS) $(tcpserver_LDADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipcclient-ipcclient.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipcserver-ipcserver.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mapnotify-mapnotify.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simplelog-simplelog.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcpclient-tcpclient.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcpserver-tcpserver.Po@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
ipcclient-ipcclient.o: ipcclient.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ipcclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ipcclient-ipcclient.o -MD -MP -MF $(DEPDIR)/ipcclient-ipcclient.Tpo -c -o ipcclient-ipcclient.o `test -f 'ipcclient.c' || echo '$(srcdir)/'`ipcclient.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ipcclient-ipcclient.Tpo $(DEPDIR)/ipcclient-ipcclient.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ipcclient.c' object='ipcclient-ipcclient.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ipcclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ipcclient-ipcclient.o `test -f 'ipcclient.c' || echo '$(srcdir)/'`ipcclient.c
|
||||
|
||||
ipcclient-ipcclient.obj: ipcclient.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ipcclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ipcclient-ipcclient.obj -MD -MP -MF $(DEPDIR)/ipcclient-ipcclient.Tpo -c -o ipcclient-ipcclient.obj `if test -f 'ipcclient.c'; then $(CYGPATH_W) 'ipcclient.c'; else $(CYGPATH_W) '$(srcdir)/ipcclient.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ipcclient-ipcclient.Tpo $(DEPDIR)/ipcclient-ipcclient.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ipcclient.c' object='ipcclient-ipcclient.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ipcclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ipcclient-ipcclient.obj `if test -f 'ipcclient.c'; then $(CYGPATH_W) 'ipcclient.c'; else $(CYGPATH_W) '$(srcdir)/ipcclient.c'; fi`
|
||||
|
||||
ipcserver-ipcserver.o: ipcserver.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ipcserver_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ipcserver-ipcserver.o -MD -MP -MF $(DEPDIR)/ipcserver-ipcserver.Tpo -c -o ipcserver-ipcserver.o `test -f 'ipcserver.c' || echo '$(srcdir)/'`ipcserver.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ipcserver-ipcserver.Tpo $(DEPDIR)/ipcserver-ipcserver.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ipcserver.c' object='ipcserver-ipcserver.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ipcserver_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ipcserver-ipcserver.o `test -f 'ipcserver.c' || echo '$(srcdir)/'`ipcserver.c
|
||||
|
||||
ipcserver-ipcserver.obj: ipcserver.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ipcserver_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ipcserver-ipcserver.obj -MD -MP -MF $(DEPDIR)/ipcserver-ipcserver.Tpo -c -o ipcserver-ipcserver.obj `if test -f 'ipcserver.c'; then $(CYGPATH_W) 'ipcserver.c'; else $(CYGPATH_W) '$(srcdir)/ipcserver.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ipcserver-ipcserver.Tpo $(DEPDIR)/ipcserver-ipcserver.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ipcserver.c' object='ipcserver-ipcserver.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ipcserver_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ipcserver-ipcserver.obj `if test -f 'ipcserver.c'; then $(CYGPATH_W) 'ipcserver.c'; else $(CYGPATH_W) '$(srcdir)/ipcserver.c'; fi`
|
||||
|
||||
mapnotify-mapnotify.o: mapnotify.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mapnotify_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mapnotify-mapnotify.o -MD -MP -MF $(DEPDIR)/mapnotify-mapnotify.Tpo -c -o mapnotify-mapnotify.o `test -f 'mapnotify.c' || echo '$(srcdir)/'`mapnotify.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mapnotify-mapnotify.Tpo $(DEPDIR)/mapnotify-mapnotify.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mapnotify.c' object='mapnotify-mapnotify.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mapnotify_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mapnotify-mapnotify.o `test -f 'mapnotify.c' || echo '$(srcdir)/'`mapnotify.c
|
||||
|
||||
mapnotify-mapnotify.obj: mapnotify.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mapnotify_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mapnotify-mapnotify.obj -MD -MP -MF $(DEPDIR)/mapnotify-mapnotify.Tpo -c -o mapnotify-mapnotify.obj `if test -f 'mapnotify.c'; then $(CYGPATH_W) 'mapnotify.c'; else $(CYGPATH_W) '$(srcdir)/mapnotify.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mapnotify-mapnotify.Tpo $(DEPDIR)/mapnotify-mapnotify.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mapnotify.c' object='mapnotify-mapnotify.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mapnotify_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mapnotify-mapnotify.obj `if test -f 'mapnotify.c'; then $(CYGPATH_W) 'mapnotify.c'; else $(CYGPATH_W) '$(srcdir)/mapnotify.c'; fi`
|
||||
|
||||
simplelog-simplelog.o: simplelog.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(simplelog_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT simplelog-simplelog.o -MD -MP -MF $(DEPDIR)/simplelog-simplelog.Tpo -c -o simplelog-simplelog.o `test -f 'simplelog.c' || echo '$(srcdir)/'`simplelog.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/simplelog-simplelog.Tpo $(DEPDIR)/simplelog-simplelog.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='simplelog.c' object='simplelog-simplelog.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(simplelog_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o simplelog-simplelog.o `test -f 'simplelog.c' || echo '$(srcdir)/'`simplelog.c
|
||||
|
||||
simplelog-simplelog.obj: simplelog.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(simplelog_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT simplelog-simplelog.obj -MD -MP -MF $(DEPDIR)/simplelog-simplelog.Tpo -c -o simplelog-simplelog.obj `if test -f 'simplelog.c'; then $(CYGPATH_W) 'simplelog.c'; else $(CYGPATH_W) '$(srcdir)/simplelog.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/simplelog-simplelog.Tpo $(DEPDIR)/simplelog-simplelog.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='simplelog.c' object='simplelog-simplelog.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(simplelog_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o simplelog-simplelog.obj `if test -f 'simplelog.c'; then $(CYGPATH_W) 'simplelog.c'; else $(CYGPATH_W) '$(srcdir)/simplelog.c'; fi`
|
||||
|
||||
tcpclient-tcpclient.o: tcpclient.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tcpclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tcpclient-tcpclient.o -MD -MP -MF $(DEPDIR)/tcpclient-tcpclient.Tpo -c -o tcpclient-tcpclient.o `test -f 'tcpclient.c' || echo '$(srcdir)/'`tcpclient.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/tcpclient-tcpclient.Tpo $(DEPDIR)/tcpclient-tcpclient.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tcpclient.c' object='tcpclient-tcpclient.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tcpclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tcpclient-tcpclient.o `test -f 'tcpclient.c' || echo '$(srcdir)/'`tcpclient.c
|
||||
|
||||
tcpclient-tcpclient.obj: tcpclient.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tcpclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tcpclient-tcpclient.obj -MD -MP -MF $(DEPDIR)/tcpclient-tcpclient.Tpo -c -o tcpclient-tcpclient.obj `if test -f 'tcpclient.c'; then $(CYGPATH_W) 'tcpclient.c'; else $(CYGPATH_W) '$(srcdir)/tcpclient.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/tcpclient-tcpclient.Tpo $(DEPDIR)/tcpclient-tcpclient.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tcpclient.c' object='tcpclient-tcpclient.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tcpclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tcpclient-tcpclient.obj `if test -f 'tcpclient.c'; then $(CYGPATH_W) 'tcpclient.c'; else $(CYGPATH_W) '$(srcdir)/tcpclient.c'; fi`
|
||||
|
||||
tcpserver-tcpserver.o: tcpserver.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tcpserver_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tcpserver-tcpserver.o -MD -MP -MF $(DEPDIR)/tcpserver-tcpserver.Tpo -c -o tcpserver-tcpserver.o `test -f 'tcpserver.c' || echo '$(srcdir)/'`tcpserver.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/tcpserver-tcpserver.Tpo $(DEPDIR)/tcpserver-tcpserver.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tcpserver.c' object='tcpserver-tcpserver.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tcpserver_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tcpserver-tcpserver.o `test -f 'tcpserver.c' || echo '$(srcdir)/'`tcpserver.c
|
||||
|
||||
tcpserver-tcpserver.obj: tcpserver.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tcpserver_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tcpserver-tcpserver.obj -MD -MP -MF $(DEPDIR)/tcpserver-tcpserver.Tpo -c -o tcpserver-tcpserver.obj `if test -f 'tcpserver.c'; then $(CYGPATH_W) 'tcpserver.c'; else $(CYGPATH_W) '$(srcdir)/tcpserver.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/tcpserver-tcpserver.Tpo $(DEPDIR)/tcpserver-tcpserver.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tcpserver.c' object='tcpserver-tcpserver.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tcpserver_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tcpserver-tcpserver.obj `if test -f 'tcpserver.c'; then $(CYGPATH_W) 'tcpserver.c'; else $(CYGPATH_W) '$(srcdir)/tcpserver.c'; fi`
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(PROGRAMS)
|
||||
installdirs:
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool clean-noinstPROGRAMS ctags distclean \
|
||||
distclean-compile distclean-generic distclean-libtool \
|
||||
distclean-tags distdir dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am install-man \
|
||||
install-pdf install-pdf-am install-ps install-ps-am \
|
||||
install-strip installcheck installcheck-am installdirs \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
|
||||
pdf pdf-am ps ps-am tags uninstall uninstall-am
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
90
examples/ipcclient.c
Normal file
90
examples/ipcclient.c
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
#include <signal.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbutil.h>
|
||||
#include <qb/qbipcc.h>
|
||||
|
||||
#define MAX_MSG_SIZE (8192)
|
||||
|
||||
struct my_req {
|
||||
struct qb_ipc_request_header hdr;
|
||||
char message[256];
|
||||
};
|
||||
|
||||
struct my_res {
|
||||
struct qb_ipc_response_header hdr;
|
||||
char message[256];
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
qb_ipcc_connection_t *conn;
|
||||
int32_t rc;
|
||||
struct my_req req;
|
||||
struct my_res res;
|
||||
char *newline;
|
||||
|
||||
conn = qb_ipcc_connect("ipcserver", MAX_MSG_SIZE);
|
||||
if (conn == NULL) {
|
||||
perror("qb_ipcc_connect");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while(1) {
|
||||
printf("SEND (q or Q to quit) : ");
|
||||
if (fgets(req.message, 256, stdin) == NULL) {
|
||||
continue;
|
||||
}
|
||||
newline = strrchr(req.message, '\n');
|
||||
if (newline) {
|
||||
*newline = '\0';
|
||||
}
|
||||
|
||||
if (strcasecmp(req.message, "q") == 0) {
|
||||
break;
|
||||
} else {
|
||||
req.hdr.id = QB_IPC_MSG_USER_START + 3;
|
||||
req.hdr.size = sizeof(struct my_req);
|
||||
rc = qb_ipcc_send(conn, &req, req.hdr.size);
|
||||
if (rc < 0) {
|
||||
perror("qb_ipcc_send");
|
||||
}
|
||||
}
|
||||
|
||||
if (rc > 0) {
|
||||
rc = qb_ipcc_recv(conn,
|
||||
&res,
|
||||
sizeof(res), -1);
|
||||
if (rc < 0) {
|
||||
perror("qb_ipcc_recv");
|
||||
}
|
||||
printf("Response[%d]: %s \n", res.hdr.id, res.message);
|
||||
}
|
||||
}
|
||||
|
||||
qb_ipcc_disconnect(conn);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
328
examples/ipcserver.c
Normal file
328
examples/ipcserver.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
#include <signal.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbutil.h>
|
||||
#include <qb/qblog.h>
|
||||
#include <qb/qbloop.h>
|
||||
#include <qb/qbipcs.h>
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
#include <glib.h>
|
||||
static GMainLoop *glib_loop;
|
||||
static qb_array_t *gio_map;
|
||||
#endif /* HAVE_GLIB */
|
||||
|
||||
static int32_t use_glib = QB_FALSE;
|
||||
static qb_loop_t *bms_loop;
|
||||
static qb_ipcs_service_t* s1;
|
||||
|
||||
static int32_t
|
||||
s1_connection_accept_fn(qb_ipcs_connection_t *c, uid_t uid, gid_t gid)
|
||||
{
|
||||
#if 0
|
||||
if (uid == 0 && gid == 0) {
|
||||
qb_log(LOG_INFO, "Authenticated connection");
|
||||
return 1;
|
||||
}
|
||||
qb_log(LOG_NOTICE, "BAD user!");
|
||||
return 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
s1_connection_created_fn(qb_ipcs_connection_t *c)
|
||||
{
|
||||
struct qb_ipcs_stats srv_stats;
|
||||
|
||||
qb_ipcs_stats_get(s1, &srv_stats, QB_FALSE);
|
||||
qb_log(LOG_INFO, "Connection created (active:%d, closed:%d)",
|
||||
srv_stats.active_connections,
|
||||
srv_stats.closed_connections);
|
||||
}
|
||||
|
||||
static void
|
||||
s1_connection_destroyed_fn(qb_ipcs_connection_t *c)
|
||||
{
|
||||
qb_log(LOG_INFO, "Connection about to be freed");
|
||||
}
|
||||
|
||||
static int32_t
|
||||
s1_connection_closed_fn(qb_ipcs_connection_t *c)
|
||||
{
|
||||
struct qb_ipcs_connection_stats stats;
|
||||
struct qb_ipcs_stats srv_stats;
|
||||
|
||||
qb_ipcs_stats_get(s1, &srv_stats, QB_FALSE);
|
||||
qb_ipcs_connection_stats_get(c, &stats, QB_FALSE);
|
||||
qb_log(LOG_INFO, "Connection to pid:%d destroyed (active:%d, closed:%d)",
|
||||
stats.client_pid,
|
||||
srv_stats.active_connections,
|
||||
srv_stats.closed_connections);
|
||||
|
||||
qb_log(LOG_DEBUG, " Requests %"PRIu64"", stats.requests);
|
||||
qb_log(LOG_DEBUG, " Responses %"PRIu64"", stats.responses);
|
||||
qb_log(LOG_DEBUG, " Events %"PRIu64"", stats.events);
|
||||
qb_log(LOG_DEBUG, " Send retries %"PRIu64"", stats.send_retries);
|
||||
qb_log(LOG_DEBUG, " Recv retries %"PRIu64"", stats.recv_retries);
|
||||
qb_log(LOG_DEBUG, " FC state %d", stats.flow_control_state);
|
||||
qb_log(LOG_DEBUG, " FC count %"PRIu64"", stats.flow_control_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
s1_msg_process_fn(qb_ipcs_connection_t *c,
|
||||
void *data, size_t size)
|
||||
{
|
||||
struct qb_ipc_request_header *req_pt = (struct qb_ipc_request_header *)data;
|
||||
struct qb_ipc_response_header response;
|
||||
ssize_t res;
|
||||
struct iovec iov[2];
|
||||
char resp[100];
|
||||
|
||||
qb_log(LOG_DEBUG, "msg received (id:%d, size:%d)",
|
||||
req_pt->id, req_pt->size);
|
||||
response.size = sizeof(struct qb_ipc_response_header);
|
||||
response.id = 13;
|
||||
response.error = 0;
|
||||
|
||||
snprintf(resp, 100, "ACK %zd bytes", size);
|
||||
iov[0].iov_len = sizeof(response);
|
||||
iov[0].iov_base = &response;
|
||||
iov[1].iov_len = strlen(resp) + 1;
|
||||
iov[1].iov_base = resp;
|
||||
|
||||
res = qb_ipcs_response_sendv(c, iov, 2);
|
||||
if (res < 0) {
|
||||
qb_perror(LOG_ERR, "qb_ipcs_response_send");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sigusr1_handler(int32_t num)
|
||||
{
|
||||
qb_log(LOG_DEBUG, "(%d)", num);
|
||||
qb_ipcs_destroy(s1);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
show_usage(const char *name)
|
||||
{
|
||||
printf("usage: \n");
|
||||
printf("%s <options>\n", name);
|
||||
printf("\n");
|
||||
printf(" options:\n");
|
||||
printf("\n");
|
||||
printf(" -h show this help text\n");
|
||||
printf(" -m use shared memory\n");
|
||||
printf(" -p use posix message queues\n");
|
||||
printf(" -s use sysv message queues\n");
|
||||
printf(" -u use unix sockets\n");
|
||||
printf(" -g use glib mainloop\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
struct gio_to_qb_poll {
|
||||
gboolean is_used;
|
||||
GIOChannel *channel;
|
||||
int32_t events;
|
||||
void * data;
|
||||
qb_ipcs_dispatch_fn_t fn;
|
||||
enum qb_loop_priority p;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
gio_read_socket (GIOChannel *gio, GIOCondition condition, gpointer data)
|
||||
{
|
||||
struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
|
||||
gint fd = g_io_channel_unix_get_fd(gio);
|
||||
|
||||
return (adaptor->fn(fd, condition, adaptor->data) == 0);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_g_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
|
||||
void *data, qb_ipcs_dispatch_fn_t fn)
|
||||
{
|
||||
struct gio_to_qb_poll *adaptor;
|
||||
GIOChannel *channel;
|
||||
int32_t res = 0;
|
||||
|
||||
res = qb_array_index(gio_map, fd, (void**)&adaptor);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
if (adaptor->is_used) {
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
channel = g_io_channel_unix_new(fd);
|
||||
if (!channel) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
adaptor->channel = channel;
|
||||
adaptor->fn = fn;
|
||||
adaptor->events = evts;
|
||||
adaptor->data = data;
|
||||
adaptor->p = p;
|
||||
adaptor->is_used = TRUE;
|
||||
|
||||
g_io_add_watch(channel, evts, gio_read_socket, adaptor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_g_dispatch_mod(enum qb_loop_priority p, int32_t fd, int32_t evts,
|
||||
void *data, qb_ipcs_dispatch_fn_t fn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_g_dispatch_del(int32_t fd)
|
||||
{
|
||||
struct gio_to_qb_poll *adaptor;
|
||||
if (qb_array_index(gio_map, fd, (void**)&adaptor) == 0) {
|
||||
g_io_channel_unref(adaptor->channel);
|
||||
adaptor->is_used = FALSE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_GLIB */
|
||||
|
||||
static int32_t
|
||||
my_job_add(enum qb_loop_priority p, void *data, qb_loop_job_dispatch_fn fn)
|
||||
{
|
||||
return qb_loop_job_add(bms_loop, p, data, fn);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
|
||||
void *data, qb_ipcs_dispatch_fn_t fn)
|
||||
{
|
||||
return qb_loop_poll_add(bms_loop, p, fd, evts, data, fn);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_dispatch_mod(enum qb_loop_priority p, int32_t fd, int32_t evts,
|
||||
void *data, qb_ipcs_dispatch_fn_t fn)
|
||||
{
|
||||
return qb_loop_poll_mod(bms_loop, p, fd, evts, data, fn);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_dispatch_del(int32_t fd)
|
||||
{
|
||||
return qb_loop_poll_del(bms_loop, fd);
|
||||
}
|
||||
|
||||
int32_t
|
||||
main(int32_t argc, char *argv[])
|
||||
{
|
||||
const char *options = "mpsugh";
|
||||
int32_t opt;
|
||||
enum qb_ipc_type ipc_type = QB_IPC_SHM;
|
||||
struct qb_ipcs_service_handlers sh = {
|
||||
.connection_accept = s1_connection_accept_fn,
|
||||
.connection_created = s1_connection_created_fn,
|
||||
.msg_process = s1_msg_process_fn,
|
||||
.connection_destroyed = s1_connection_destroyed_fn,
|
||||
.connection_closed = s1_connection_closed_fn,
|
||||
};
|
||||
struct qb_ipcs_poll_handlers ph = {
|
||||
.job_add = my_job_add,
|
||||
.dispatch_add = my_dispatch_add,
|
||||
.dispatch_mod = my_dispatch_mod,
|
||||
.dispatch_del = my_dispatch_del,
|
||||
};
|
||||
#ifdef HAVE_GLIB
|
||||
struct qb_ipcs_poll_handlers glib_ph = {
|
||||
.job_add = NULL, /* FIXME */
|
||||
.dispatch_add = my_g_dispatch_add,
|
||||
.dispatch_mod = my_g_dispatch_mod,
|
||||
.dispatch_del = my_g_dispatch_del,
|
||||
};
|
||||
#endif /* HAVE_GLIB */
|
||||
|
||||
while ((opt = getopt(argc, argv, options)) != -1) {
|
||||
switch (opt) {
|
||||
case 'm':
|
||||
ipc_type = QB_IPC_SHM;
|
||||
break;
|
||||
case 's':
|
||||
ipc_type = QB_IPC_SYSV_MQ;
|
||||
break;
|
||||
case 'u':
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
break;
|
||||
case 'p':
|
||||
ipc_type = QB_IPC_POSIX_MQ;
|
||||
break;
|
||||
case 'g':
|
||||
use_glib = QB_TRUE;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
show_usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
signal(SIGINT, sigusr1_handler);
|
||||
|
||||
qb_log_init("ipcserver", LOG_USER, LOG_WARNING);
|
||||
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_FILE, __FILE__,
|
||||
LOG_DEBUG);
|
||||
qb_log_format_set(QB_LOG_STDERR, "%f:%l [%p] %b");
|
||||
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
|
||||
s1 = qb_ipcs_create("ipcserver", 0, ipc_type, &sh);
|
||||
if (s1 == 0) {
|
||||
qb_perror(LOG_ERR, "qb_ipcs_create");
|
||||
exit(1);
|
||||
}
|
||||
if (!use_glib) {
|
||||
bms_loop = qb_loop_create();
|
||||
qb_ipcs_poll_handlers_set(s1, &ph);
|
||||
qb_ipcs_run(s1);
|
||||
qb_loop_run(bms_loop);
|
||||
} else {
|
||||
#ifdef HAVE_GLIB
|
||||
glib_loop = g_main_loop_new(NULL, FALSE);
|
||||
gio_map = qb_array_create_2(16, sizeof(struct gio_to_qb_poll), 1);
|
||||
qb_ipcs_poll_handlers_set(s1, &glib_ph);
|
||||
qb_ipcs_run(s1);
|
||||
g_main_loop_run(glib_loop);
|
||||
#else
|
||||
qb_log(LOG_ERR, "You don't seem to have glib-devel installed.\n");
|
||||
#endif
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
208
examples/mapnotify.c
Normal file
208
examples/mapnotify.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse <jfriesse@redhat.com>
|
||||
* Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbutil.h>
|
||||
#include <qb/qbmap.h>
|
||||
|
||||
static void
|
||||
notify_fn(uint32_t event, char* key, void* old_value, void* value, void* user_data)
|
||||
{
|
||||
if (event == QB_MAP_NOTIFY_FREE) {
|
||||
fprintf(stderr, "Notify[FREE] %s [%d]\n",
|
||||
key, *(int *)old_value);
|
||||
free(old_value);
|
||||
} else if (event == QB_MAP_NOTIFY_DELETED) {
|
||||
fprintf(stderr, "Notify[DELETED] %s [%d]\n",
|
||||
key, *(int *)old_value);
|
||||
} else if (event == QB_MAP_NOTIFY_REPLACED) {
|
||||
fprintf(stderr, "Notify[REPLACED] %s [%d] -> [%d]\n",
|
||||
key, *(int *)old_value, *(int *)value);
|
||||
} else {
|
||||
fprintf(stderr, "Notify[%d] %s \n", event, key);
|
||||
if (value != NULL) {
|
||||
fprintf(stderr, " value = [%d]\n", *(int *)value);
|
||||
}
|
||||
if (old_value != NULL) {
|
||||
fprintf(stderr, " old value = [%d]\n", *(int *)old_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_cs_keys(qb_map_t *m)
|
||||
{
|
||||
qb_map_put(m, "compatibility", strdup("none"));
|
||||
qb_map_put(m, "totem.version", strdup("2"));
|
||||
qb_map_put(m, "totem.secauth", strdup("off"));
|
||||
qb_map_put(m, "totem.threads", strdup("0"));
|
||||
qb_map_put(m, "totem.interface.ringnumber", strdup("0"));
|
||||
qb_map_put(m, "totem.interface.bindnetaddr", strdup("192.168.122.1"));
|
||||
qb_map_put(m, "totem.interface.mcastaddr", strdup("239.255.1.1"));
|
||||
qb_map_put(m, "totem.interface.mcastport", strdup("5405"));
|
||||
qb_map_put(m, "totem.interface.ttl", strdup("1"));
|
||||
qb_map_put(m, "logging.to_stderr", strdup("yes"));
|
||||
qb_map_put(m, "logging.to_logfile", strdup("no"));
|
||||
qb_map_put(m, "logging.logfile", strdup("/var/log/cluster/corosync.log"));
|
||||
qb_map_put(m, "logging.to_syslog", strdup("no"));
|
||||
qb_map_put(m, "logging.debug", strdup("off"));
|
||||
qb_map_put(m, "logging.timestamp", strdup("on"));
|
||||
qb_map_put(m, "logging.logger_subsys.subsys", strdup("MAIN"));
|
||||
qb_map_put(m, "logging.logger_subsys.debug", strdup("on"));
|
||||
qb_map_put(m, "amf.mode", strdup("disabled"));
|
||||
qb_map_put(m, "quorum.provider", strdup("corosync_quorum_ykd"));
|
||||
qb_map_put(m, "runtime.services.evs.service_id", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.evs.0.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.evs.0.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cfg.service_id", strdup("7"));
|
||||
qb_map_put(m, "runtime.services.cfg.0.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cfg.0.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cfg.1.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cfg.1.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cfg.2.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cfg.2.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cfg.3.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cfg.3.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cpg.service_id", strdup("8"));
|
||||
qb_map_put(m, "runtime.services.cpg.0.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cpg.0.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cpg.1.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cpg.1.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cpg.2.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cpg.2.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cpg.3.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cpg.3.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cpg.4.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cpg.4.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.cpg.5.tx", strdup("1"));
|
||||
qb_map_put(m, "runtime.services.cpg.5.rx", strdup("1"));
|
||||
qb_map_put(m, "runtime.services.confdb.service_id", strdup("11"));
|
||||
qb_map_put(m, "runtime.services.pload.service_id", strdup("13"));
|
||||
qb_map_put(m, "runtime.services.pload.0.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.pload.0.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.pload.1.tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.pload.1.rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.services.quorum.service_id", strdup("12"));
|
||||
qb_map_put(m, "runtime.connections.active", strdup("1"));
|
||||
qb_map_put(m, "runtime.connections.closed", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.service_id", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.client_pid", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.responses", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.dispatched", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.requests", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.send_retries", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.recv_retries", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.flow_control", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.flow_control_count", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.queue_size", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.invalid_request", strdup("0"));
|
||||
qb_map_put(m, "runtime.connections.corosync-objctl:24175:0x17fd2b0.overload", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.msg_reserved", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.msg_queue_avail", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.orf_token_tx", strdup("1"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.orf_token_rx", strdup("100"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.memb_merge_detect_tx", strdup("29"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.memb_merge_detect_rx", strdup("29"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.memb_join_tx", strdup("1"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.memb_join_rx", strdup("1"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.mcast_tx", strdup("13"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.mcast_retx", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.mcast_rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.memb_commit_token_tx", strdup("2"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.memb_commit_token_rx", strdup("2"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.token_hold_cancel_tx", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.token_hold_cancel_rx", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.operational_entered", strdup("1"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.operational_token_lost", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.gather_entered", strdup("1"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.gather_token_lost", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.commit_entered", strdup("1"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.commit_token_lost", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.recovery_entered", strdup("1"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.recovery_token_lost", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.consensus_timeouts", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.mtt_rx_token", strdup("106"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.avg_token_workload", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.avg_backlog_calc", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.rx_msg_dropped", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.continuous_gather", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.firewall_enabled_or_nic_failure", strdup("0"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.members.24815808.ip", strdup("r(0) ip(192.168.122.1) "));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.members.24815808.join_count", strdup("1"));
|
||||
qb_map_put(m, "runtime.totem.pg.mrp.srp.members.24815808.status", strdup("joined"));
|
||||
qb_map_put(m, "runtime.blackbox.dump_flight_data", strdup("no"));
|
||||
qb_map_put(m, "runtime.blackbox.dump_state", strdup("no"));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
qb_map_t *trie;
|
||||
int *i1, *i2, *i3;
|
||||
qb_map_iter_t *iter;
|
||||
const char *key;
|
||||
void *val;
|
||||
uint32_t revents = (QB_MAP_NOTIFY_DELETED |
|
||||
QB_MAP_NOTIFY_REPLACED |
|
||||
QB_MAP_NOTIFY_INSERTED |
|
||||
QB_MAP_NOTIFY_RECURSIVE);
|
||||
|
||||
trie = qb_trie_create();
|
||||
assert(trie != NULL);
|
||||
qb_trie_dump(trie);
|
||||
add_cs_keys(trie);
|
||||
|
||||
i1 = malloc(sizeof(int));
|
||||
assert(i1 != NULL);
|
||||
*i1 = 1;
|
||||
|
||||
i2 = malloc(sizeof(int));
|
||||
assert(i2 != NULL);
|
||||
*i2 = 2;
|
||||
|
||||
i3 = malloc(sizeof(int));
|
||||
assert(i3 != NULL);
|
||||
*i3 = 3;
|
||||
|
||||
qb_map_notify_add(trie, NULL, notify_fn, QB_MAP_NOTIFY_FREE, NULL);
|
||||
|
||||
qb_map_put(trie, "test.key1", i1);
|
||||
qb_map_put(trie, "test.key2", i2);
|
||||
|
||||
qb_map_notify_add(trie, "test.", notify_fn, revents, NULL);
|
||||
qb_trie_dump(trie);
|
||||
|
||||
qb_map_put(trie, "test.key1", i3);
|
||||
|
||||
iter = qb_map_pref_iter_create(trie, "test.");
|
||||
while ((key = qb_map_iter_next(iter, &val)) != NULL) {
|
||||
fprintf(stderr,"Iter %s [%d]\n", key, *(int*)val);
|
||||
qb_map_rm(trie, key);
|
||||
}
|
||||
qb_map_iter_free(iter);
|
||||
qb_map_notify_del_2(trie, "test.", notify_fn, revents, NULL);
|
||||
qb_map_destroy(trie);
|
||||
|
||||
return (0);
|
||||
}
|
||||
247
examples/simplelog.c
Normal file
247
examples/simplelog.c
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
#include <signal.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qblog.h>
|
||||
|
||||
#define MY_TAG_ONE (1)
|
||||
#define MY_TAG_TWO (1 << 1)
|
||||
#define MY_TAG_THREE (1 << 2)
|
||||
|
||||
static int32_t _log_priority = LOG_WARNING;
|
||||
|
||||
static void func_one(void)
|
||||
{
|
||||
FILE* fd;
|
||||
|
||||
qb_enter();
|
||||
qb_logt(LOG_DEBUG, MY_TAG_TWO, "arf arf?");
|
||||
qb_logt(LOG_CRIT, MY_TAG_THREE, "arrrg!");
|
||||
qb_logt(134, MY_TAG_THREE, "big priority");
|
||||
qb_logt(LOG_ERR, MY_TAG_THREE, "oops, I did it again");
|
||||
qb_log(LOG_INFO, "are you aware ...");
|
||||
|
||||
fd = fopen("/nothing.txt", "r+");
|
||||
if (fd == NULL) {
|
||||
qb_perror(LOG_ERR, "can't open(\"/nothing.txt\")");
|
||||
} else {
|
||||
fclose(fd);
|
||||
}
|
||||
qb_leave();
|
||||
}
|
||||
|
||||
static void func_two(void)
|
||||
{
|
||||
qb_enter();
|
||||
qb_logt(LOG_DEBUG, 0, "arf arf?");
|
||||
qb_logt(LOG_CRIT, MY_TAG_ONE, "arrrg!");
|
||||
qb_log(LOG_ERR, "oops, I did it again");
|
||||
qb_logt(LOG_INFO, MY_TAG_THREE, "are you aware ...");
|
||||
qb_leave();
|
||||
}
|
||||
|
||||
static void show_usage(const char *name)
|
||||
{
|
||||
printf("usage: \n");
|
||||
printf("%s <options>\n", name);
|
||||
printf("\n");
|
||||
printf(" options:\n");
|
||||
printf("\n");
|
||||
printf(" -v verbose\n");
|
||||
printf(" -t threaded logging\n");
|
||||
printf(" -e log to stderr\n");
|
||||
printf(" -b log to blackbox\n");
|
||||
printf(" -f <filename> log to a file\n");
|
||||
printf(" -h show this help text\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int32_t do_blackbox = QB_FALSE;
|
||||
static int32_t do_threaded = QB_FALSE;
|
||||
|
||||
static void sigsegv_handler(int sig)
|
||||
{
|
||||
(void)signal (SIGSEGV, SIG_DFL);
|
||||
qb_log_fini();
|
||||
if (do_blackbox) {
|
||||
qb_log_blackbox_write_to_file("simple-log.fdata");
|
||||
}
|
||||
raise(SIGSEGV);
|
||||
}
|
||||
|
||||
static const char *my_tags_stringify(uint32_t tags)
|
||||
{
|
||||
if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT)) {
|
||||
return "libqb";
|
||||
} else if (qb_bit_is_set(tags, 0)) {
|
||||
return "ONE";
|
||||
} else if (qb_bit_is_set(tags, 1)) {
|
||||
return "TWO";
|
||||
} else if (qb_bit_is_set(tags, 2)) {
|
||||
return "THREE";
|
||||
} else {
|
||||
return "MAIN";
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
trace_logger(int32_t t,
|
||||
struct qb_log_callsite *cs,
|
||||
time_t timestamp,
|
||||
const char *msg)
|
||||
{
|
||||
char output_buffer[QB_LOG_MAX_LEN];
|
||||
output_buffer[0] = '\0';
|
||||
qb_log_target_format(t, cs, timestamp, msg, output_buffer);
|
||||
fprintf(stderr, "%s\n", output_buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
m_filter(struct qb_log_callsite *cs)
|
||||
{
|
||||
if ((cs->priority >= LOG_ALERT &&
|
||||
cs->priority <= _log_priority) &&
|
||||
strcmp(cs->filename, __FILE__) == 0) {
|
||||
qb_bit_set(cs->targets, QB_LOG_STDERR);
|
||||
} else {
|
||||
qb_bit_clear(cs->targets, QB_LOG_STDERR);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t main(int32_t argc, char *argv[])
|
||||
{
|
||||
const char *options = "vhteobdf:";
|
||||
int32_t opt;
|
||||
int32_t tracer;
|
||||
int32_t do_stderr = QB_FALSE;
|
||||
int32_t do_stdout = QB_FALSE;
|
||||
int32_t do_dump_blackbox = QB_FALSE;
|
||||
char *logfile = NULL;
|
||||
int32_t log_fd = -1;
|
||||
|
||||
while ((opt = getopt(argc, argv, options)) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
do_dump_blackbox = QB_TRUE;
|
||||
break;
|
||||
case 't':
|
||||
do_threaded = QB_TRUE;
|
||||
break;
|
||||
case 'e':
|
||||
do_stderr = QB_TRUE;
|
||||
break;
|
||||
case 'o':
|
||||
do_stdout = QB_TRUE;
|
||||
break;
|
||||
case 'b':
|
||||
do_blackbox = QB_TRUE;
|
||||
break;
|
||||
case 'f':
|
||||
logfile = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
_log_priority++;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
show_usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_dump_blackbox) {
|
||||
qb_log_blackbox_print_from_file("simple-log.fdata");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
signal(SIGSEGV, sigsegv_handler);
|
||||
|
||||
qb_log_init("simple-log", LOG_USER, LOG_INFO);
|
||||
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_THREADED, do_threaded);
|
||||
qb_log_tags_stringify_fn_set(my_tags_stringify);
|
||||
|
||||
|
||||
if (do_stderr) {
|
||||
qb_log_filter_fn_set(m_filter);
|
||||
qb_log_format_set(QB_LOG_STDERR, "[%p] %4g: %f:%l %b");
|
||||
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
|
||||
tracer = qb_log_custom_open(trace_logger, NULL, NULL, NULL);
|
||||
qb_log_ctl(tracer, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
qb_log_format_set(tracer, "%4g: %n() %b");
|
||||
qb_log_filter_ctl2(tracer, QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_FILE, __FILE__,
|
||||
LOG_TRACE, 200);
|
||||
}
|
||||
if (do_stdout) {
|
||||
qb_log_filter_ctl2(QB_LOG_STDOUT, QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_FILE, __FILE__,
|
||||
LOG_ALERT, QB_MIN(LOG_DEBUG, _log_priority));
|
||||
qb_log_format_set(QB_LOG_STDOUT, "[%p] %4g: %f:%l %b");
|
||||
qb_log_ctl(QB_LOG_STDOUT, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
}
|
||||
if (do_blackbox) {
|
||||
qb_log_filter_ctl(QB_LOG_BLACKBOX, QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
|
||||
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 4096);
|
||||
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_THREADED, QB_FALSE);
|
||||
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
}
|
||||
if (logfile) {
|
||||
log_fd = qb_log_file_open(logfile);
|
||||
qb_log_filter_ctl(log_fd, QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_FILE, __FILE__, _log_priority);
|
||||
qb_log_format_set(log_fd, "[%N] %t %n() [%p] %b");
|
||||
qb_log_ctl(log_fd, QB_LOG_CONF_THREADED, do_threaded);
|
||||
qb_log_ctl(log_fd, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
}
|
||||
if (do_threaded) {
|
||||
qb_log_thread_start();
|
||||
}
|
||||
qb_log(LOG_DEBUG, "hello");
|
||||
qb_log(LOG_INFO, "this is an info");
|
||||
qb_log(LOG_NOTICE, "hello - notice?");
|
||||
func_one();
|
||||
func_two();
|
||||
|
||||
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
|
||||
|
||||
qb_log(LOG_WARNING, "no syslog");
|
||||
qb_log(LOG_ERR, "no syslog");
|
||||
|
||||
#if 0
|
||||
// test blackbox
|
||||
logfile = NULL;
|
||||
logfile[5] = 'a';
|
||||
#endif
|
||||
if (do_blackbox) {
|
||||
qb_log_blackbox_write_to_file("simple-log.fdata");
|
||||
qb_log_blackbox_print_from_file("simple-log.fdata");
|
||||
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
|
||||
}
|
||||
qb_log_fini();
|
||||
return 0;
|
||||
}
|
||||
|
||||
79
examples/tcpclient.c
Normal file
79
examples/tcpclient.c
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
#include <netdb.h>
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int sock;
|
||||
int32_t res;
|
||||
char send_data[1024];
|
||||
char recv_data[1024];
|
||||
char *newline;
|
||||
struct sockaddr_in server_addr;
|
||||
struct hostent *host = gethostbyname("127.0.0.1");
|
||||
|
||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
perror("Socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons(5000);
|
||||
memcpy(&server_addr.sin_addr, host->h_addr_list[0], sizeof(server_addr.sin_addr));
|
||||
bzero(&(server_addr.sin_zero),8);
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&server_addr,
|
||||
sizeof(struct sockaddr)) == -1) {
|
||||
perror("Connect");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while(1) {
|
||||
printf("\nSEND (q or Q to quit) : ");
|
||||
if (fgets(send_data, 1024, stdin) == NULL) {
|
||||
continue;
|
||||
}
|
||||
newline = strrchr(send_data, '\n');
|
||||
if (newline) {
|
||||
*newline = '\0';
|
||||
}
|
||||
res = send(sock, send_data, strlen(send_data), 0);
|
||||
if (strcasecmp(send_data, "q") == 0) {
|
||||
close(sock);
|
||||
printf("you typed QUIT\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (res > 0) {
|
||||
res = recv(sock, recv_data, 1024, 0);
|
||||
if (res > 0) {
|
||||
recv_data[res] = '\0';
|
||||
printf("\nResponse: %s ", recv_data);
|
||||
} else {
|
||||
perror("recv");
|
||||
}
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
152
examples/tcpserver.c
Normal file
152
examples/tcpserver.c
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbloop.h>
|
||||
|
||||
static int32_t
|
||||
sock_read_fn(int32_t fd, int32_t revents, void *data)
|
||||
{
|
||||
char recv_data[1024];
|
||||
char send_data[1024];
|
||||
int bytes_recieved;
|
||||
|
||||
if (revents & POLLHUP) {
|
||||
printf("Socket %d peer closed\n", fd);
|
||||
close(fd);
|
||||
return QB_FALSE;
|
||||
}
|
||||
|
||||
bytes_recieved = recv(fd, recv_data, 1024, 0);
|
||||
if (bytes_recieved < 0) {
|
||||
perror("recv");
|
||||
return QB_TRUE;
|
||||
}
|
||||
recv_data[bytes_recieved] = '\0';
|
||||
|
||||
if (strcmp(recv_data, "q") == 0 ||
|
||||
strcmp(recv_data, "Q") == 0) {
|
||||
printf("Quiting connection from socket %d\n", fd);
|
||||
close(fd);
|
||||
return QB_FALSE;
|
||||
} else {
|
||||
printf("Recieved: %s\n", recv_data);
|
||||
snprintf(send_data, 1024, "ACK %d bytes", bytes_recieved);
|
||||
send(fd, send_data, strlen(send_data), 0);
|
||||
}
|
||||
return QB_TRUE;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
sock_accept_fn(int32_t fd, int32_t revents, void *data)
|
||||
{
|
||||
struct sockaddr_in client_addr;
|
||||
qb_loop_t * ml = (qb_loop_t*)data;
|
||||
socklen_t sin_size = sizeof(struct sockaddr_in);
|
||||
int connected = accept(fd, (struct sockaddr *)&client_addr, &sin_size);
|
||||
|
||||
if (connected < 0) {
|
||||
perror("accept");
|
||||
return QB_TRUE;
|
||||
}
|
||||
printf("I got a connection from (%s , %d)\n",
|
||||
inet_ntoa(client_addr.sin_addr),
|
||||
ntohs(client_addr.sin_port));
|
||||
|
||||
qb_loop_poll_add(ml, QB_LOOP_MED,
|
||||
connected, POLLIN,
|
||||
ml, sock_read_fn);
|
||||
|
||||
return QB_TRUE;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
please_exit_fn(int32_t rsignal, void *data)
|
||||
{
|
||||
qb_loop_t * ml = (qb_loop_t*)data;
|
||||
|
||||
printf("Shutting down at you request...\n");
|
||||
qb_loop_stop(ml);
|
||||
return QB_FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int sock;
|
||||
int true_opt = 1;
|
||||
struct sockaddr_in server_addr;
|
||||
qb_loop_t * ml = qb_loop_create();
|
||||
|
||||
if ((sock = socket(AF_INET,
|
||||
SOCK_STREAM,
|
||||
0)) == -1) {
|
||||
perror("Socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (setsockopt(sock,
|
||||
SOL_SOCKET,
|
||||
SO_REUSEADDR,
|
||||
&true_opt,
|
||||
sizeof(int)) == -1) {
|
||||
perror("Setsockopt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons(5000);
|
||||
server_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
bzero(&(server_addr.sin_zero),8);
|
||||
|
||||
printf("TCPServer binding to port 5000\n");
|
||||
if (bind(sock,
|
||||
(struct sockaddr *)&server_addr,
|
||||
sizeof(struct sockaddr)) == -1) {
|
||||
perror("Unable to bind");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("TCPServer Waiting for client on port 5000\n");
|
||||
|
||||
if (listen(sock, 5) == -1) {
|
||||
perror("Listen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
qb_loop_poll_add(ml, QB_LOOP_MED,
|
||||
sock, POLLIN,
|
||||
ml, sock_accept_fn);
|
||||
|
||||
qb_loop_signal_add(ml, QB_LOOP_HIGH,
|
||||
SIGINT,
|
||||
ml, please_exit_fn,
|
||||
NULL);
|
||||
qb_loop_run(ml);
|
||||
|
||||
close(sock);
|
||||
return 0;
|
||||
}
|
||||
27
include/Makefile.am
Normal file
27
include/Makefile.am
Normal file
@ -0,0 +1,27 @@
|
||||
# Copyright (c) 2010 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Angus Salkeld <asalkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in config.h.in
|
||||
|
||||
EXTRA_DIST = $(noinst_HEADERS)
|
||||
noinst_HEADERS = os_base.h tlist.h
|
||||
|
||||
SUBDIRS = qb
|
||||
|
||||
629
include/Makefile.in
Normal file
629
include/Makefile.in
Normal file
@ -0,0 +1,629 @@
|
||||
# Makefile.in generated by automake 1.11.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# Copyright (c) 2010 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Angus Salkeld <asalkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = include
|
||||
DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in $(srcdir)/config.h.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = config.h $(top_builddir)/include/qb/qbconfig.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
|
||||
html-recursive info-recursive install-data-recursive \
|
||||
install-dvi-recursive install-exec-recursive \
|
||||
install-html-recursive install-info-recursive \
|
||||
install-pdf-recursive install-ps-recursive install-recursive \
|
||||
installcheck-recursive installdirs-recursive pdf-recursive \
|
||||
ps-recursive uninstall-recursive
|
||||
HEADERS = $(noinst_HEADERS)
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
|
||||
$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
|
||||
distdir
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
am__relativize = \
|
||||
dir0=`pwd`; \
|
||||
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
|
||||
sed_rest='s,^[^/]*/*,,'; \
|
||||
sed_last='s,^.*/\([^/]*\)$$,\1,'; \
|
||||
sed_butlast='s,/*[^/]*$$,,'; \
|
||||
while test -n "$$dir1"; do \
|
||||
first=`echo "$$dir1" | sed -e "$$sed_first"`; \
|
||||
if test "$$first" != "."; then \
|
||||
if test "$$first" = ".."; then \
|
||||
dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
|
||||
dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
|
||||
else \
|
||||
first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
|
||||
if test "$$first2" = "$$first"; then \
|
||||
dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
|
||||
else \
|
||||
dir2="../$$dir2"; \
|
||||
fi; \
|
||||
dir0="$$dir0"/"$$first"; \
|
||||
fi; \
|
||||
fi; \
|
||||
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
|
||||
done; \
|
||||
reldir="$$dir2"
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CHECK_CFLAGS = @CHECK_CFLAGS@
|
||||
CHECK_LIBS = @CHECK_LIBS@
|
||||
CP = @CP@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DOXYGEN = @DOXYGEN@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GLIB_CFLAGS = @GLIB_CFLAGS@
|
||||
GLIB_LIBS = @GLIB_LIBS@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIB_RT = @LIB_RT@
|
||||
LINT_FLAGS = @LINT_FLAGS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKGCONFIG = @PKGCONFIG@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
SOCKETDIR = @SOCKETDIR@
|
||||
SPLINT = @SPLINT@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
MAINTAINERCLEANFILES = Makefile.in config.h.in
|
||||
EXTRA_DIST = $(noinst_HEADERS)
|
||||
noinst_HEADERS = os_base.h tlist.h
|
||||
SUBDIRS = qb
|
||||
all: config.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu include/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
config.h: stamp-h1
|
||||
@if test ! -f $@; then rm -f stamp-h1; else :; fi
|
||||
@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi
|
||||
|
||||
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
|
||||
@rm -f stamp-h1
|
||||
cd $(top_builddir) && $(SHELL) ./config.status include/config.h
|
||||
$(srcdir)/config.h.in: $(am__configure_deps)
|
||||
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
|
||||
rm -f stamp-h1
|
||||
touch $@
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f config.h stamp-h1
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
# This directory's subdirectories are mostly independent; you can cd
|
||||
# into them and run `make' without going through this Makefile.
|
||||
# To change the values of `make' variables: instead of editing Makefiles,
|
||||
# (1) if the variable is set in `config.status', edit `config.status'
|
||||
# (which will cause the Makefiles to be regenerated when you run `make');
|
||||
# (2) otherwise, pass the desired values on the `make' command line.
|
||||
$(RECURSIVE_TARGETS):
|
||||
@fail= failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
dot_seen=yes; \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done; \
|
||||
if test "$$dot_seen" = "no"; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
|
||||
fi; test -z "$$fail"
|
||||
|
||||
$(RECURSIVE_CLEAN_TARGETS):
|
||||
@fail= failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
case "$@" in \
|
||||
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
|
||||
*) list='$(SUBDIRS)' ;; \
|
||||
esac; \
|
||||
rev=''; for subdir in $$list; do \
|
||||
if test "$$subdir" = "."; then :; else \
|
||||
rev="$$subdir $$rev"; \
|
||||
fi; \
|
||||
done; \
|
||||
rev="$$rev ."; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
for subdir in $$rev; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done && test -z "$$fail"
|
||||
tags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
|
||||
done
|
||||
ctags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
|
||||
done
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
|
||||
include_option=--etags-include; \
|
||||
empty_fix=.; \
|
||||
else \
|
||||
include_option=--include; \
|
||||
empty_fix=; \
|
||||
fi; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test ! -f $$subdir/TAGS || \
|
||||
set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
|
||||
fi; \
|
||||
done; \
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test -d "$(distdir)/$$subdir" \
|
||||
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
|
||||
$(am__relativize); \
|
||||
new_distdir=$$reldir; \
|
||||
dir1=$$subdir; dir2="$(top_distdir)"; \
|
||||
$(am__relativize); \
|
||||
new_top_distdir=$$reldir; \
|
||||
echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
|
||||
echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
|
||||
($(am__cd) $$subdir && \
|
||||
$(MAKE) $(AM_MAKEFLAGS) \
|
||||
top_distdir="$$new_top_distdir" \
|
||||
distdir="$$new_distdir" \
|
||||
am__remove_distdir=: \
|
||||
am__skip_length_check=: \
|
||||
am__skip_mode_fix=: \
|
||||
distdir) \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-recursive
|
||||
all-am: Makefile $(HEADERS) config.h
|
||||
installdirs: installdirs-recursive
|
||||
installdirs-am:
|
||||
install: install-recursive
|
||||
install-exec: install-exec-recursive
|
||||
install-data: install-data-recursive
|
||||
uninstall: uninstall-recursive
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-recursive
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
|
||||
clean: clean-recursive
|
||||
|
||||
clean-am: clean-generic clean-libtool mostlyclean-am
|
||||
|
||||
distclean: distclean-recursive
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
|
||||
|
||||
dvi: dvi-recursive
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-recursive
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-recursive
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-recursive
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-recursive
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-recursive
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-recursive
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-recursive
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-recursive
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-recursive
|
||||
|
||||
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
|
||||
|
||||
pdf: pdf-recursive
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-recursive
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \
|
||||
ctags-recursive install-am install-strip tags-recursive
|
||||
|
||||
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
|
||||
all all-am check check-am clean clean-generic clean-libtool \
|
||||
ctags ctags-recursive distclean distclean-generic \
|
||||
distclean-hdr distclean-libtool distclean-tags distdir dvi \
|
||||
dvi-am html html-am info info-am install install-am \
|
||||
install-data install-data-am install-dvi install-dvi-am \
|
||||
install-exec install-exec-am install-html install-html-am \
|
||||
install-info install-info-am install-man install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs installdirs-am \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-recursive uninstall uninstall-am
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
413
include/config.h.in
Normal file
413
include/config.h.in
Normal file
@ -0,0 +1,413 @@
|
||||
/* include/config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* building in place */
|
||||
#undef BUILDING_IN_PLACE
|
||||
|
||||
/* Compiling Debugging code */
|
||||
#undef DEBUG
|
||||
|
||||
/* Disable _POSIX_THREAD_PROCESS_SHARED */
|
||||
#undef DISABLE_POSIX_THREAD_PROCESS_SHARED
|
||||
|
||||
/* Define to 1 if you have the `alarm' function. */
|
||||
#undef HAVE_ALARM
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Define to 1 if your system has a working `chown' function. */
|
||||
#undef HAVE_CHOWN
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
#undef HAVE_CLOCK_GETTIME
|
||||
|
||||
/* "Have /usr/share/dict/words" */
|
||||
#undef HAVE_DICT_WORDS
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the `epoll_create' function. */
|
||||
#undef HAVE_EPOLL_CREATE
|
||||
|
||||
/* Define to 1 if you have the `epoll_create1' function. */
|
||||
#undef HAVE_EPOLL_CREATE1
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#undef HAVE_ERRNO_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
/* Define to 1 if you have the `ftruncate' function. */
|
||||
#undef HAVE_FTRUNCATE
|
||||
|
||||
/* have builtin atomic operations */
|
||||
#undef HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS
|
||||
|
||||
/* Define to 1 if you have the `getpagesize' function. */
|
||||
#undef HAVE_GETPAGESIZE
|
||||
|
||||
/* Define to 1 if you have the `getrlimit' function. */
|
||||
#undef HAVE_GETRLIMIT
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* We have glib */
|
||||
#undef HAVE_GLIB
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `dl' library (-ldl). */
|
||||
#undef HAVE_LIBDL
|
||||
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#undef HAVE_LIBPTHREAD
|
||||
|
||||
/* Define to 1 if you have the `rt' library (-lrt). */
|
||||
#undef HAVE_LIBRT
|
||||
|
||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
/* Define to 1 if you have the <link.h> header file. */
|
||||
#undef HAVE_LINK_H
|
||||
|
||||
/* Define to 1 if you have the `localtime' function. */
|
||||
#undef HAVE_LOCALTIME
|
||||
|
||||
/* Define to 1 if you have the `localtime_r' function. */
|
||||
#undef HAVE_LOCALTIME_R
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#undef HAVE_MEMSET
|
||||
|
||||
/* Define to 1 if you have a working `mmap' system call. */
|
||||
#undef HAVE_MMAP
|
||||
|
||||
/* Define to 1 if you have the <mqueue.h> header file. */
|
||||
#undef HAVE_MQUEUE_H
|
||||
|
||||
/* Define to 1 if you have the `munmap' function. */
|
||||
#undef HAVE_MUNMAP
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#undef HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if you have the `poll' function. */
|
||||
#undef HAVE_POLL
|
||||
|
||||
/* have posix message queues */
|
||||
#undef HAVE_POSIX_MQ
|
||||
|
||||
/* Define to 1 if you have the `pthread_setschedparam' function. */
|
||||
#undef HAVE_PTHREAD_SETSCHEDPARAM
|
||||
|
||||
/* Define to 1 if you have the `pthread_spin_lock' function. */
|
||||
#undef HAVE_PTHREAD_SPIN_LOCK
|
||||
|
||||
/* Define to 1 if you have the `rand' function. */
|
||||
#undef HAVE_RAND
|
||||
|
||||
/* Define to 1 if you have the `random' function. */
|
||||
#undef HAVE_RANDOM
|
||||
|
||||
/* Define to 1 if you have the `sched_get_priority_max' function. */
|
||||
#undef HAVE_SCHED_GET_PRIORITY_MAX
|
||||
|
||||
/* Define to 1 if you have the `sched_setscheduler' function. */
|
||||
#undef HAVE_SCHED_SETSCHEDULER
|
||||
|
||||
/* have slow tests */
|
||||
#undef HAVE_SLOW_TESTS
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#undef HAVE_SOCKET
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#undef HAVE_STRCHR
|
||||
|
||||
/* Define to 1 if you have the `strchrnul' function. */
|
||||
#undef HAVE_STRCHRNUL
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#undef HAVE_STRDUP
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strlcat' function. */
|
||||
#undef HAVE_STRLCAT
|
||||
|
||||
/* Define to 1 if you have the `strlcpy' function. */
|
||||
#undef HAVE_STRLCPY
|
||||
|
||||
/* Define to 1 if you have the `strrchr' function. */
|
||||
#undef HAVE_STRRCHR
|
||||
|
||||
/* Define to 1 if you have the `strstr' function. */
|
||||
#undef HAVE_STRSTR
|
||||
|
||||
/* Define to 1 if you have the `sysconf' function. */
|
||||
#undef HAVE_SYSCONF
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#undef HAVE_SYSLOG_H
|
||||
|
||||
/* have sysv message queues */
|
||||
#undef HAVE_SYSV_MQ
|
||||
|
||||
/* Define to 1 if you have the <sys/epoll.h> header file. */
|
||||
#undef HAVE_SYS_EPOLL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ipc.h> header file. */
|
||||
#undef HAVE_SYS_IPC_H
|
||||
|
||||
/* Define to 1 if you have the <sys/mman.h> header file. */
|
||||
#undef HAVE_SYS_MMAN_H
|
||||
|
||||
/* Define to 1 if you have the <sys/msg.h> header file. */
|
||||
#undef HAVE_SYS_MSG_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/poll.h> header file. */
|
||||
#undef HAVE_SYS_POLL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/resource.h> header file. */
|
||||
#undef HAVE_SYS_RESOURCE_H
|
||||
|
||||
/* Define to 1 if you have the <sys/sem.h> header file. */
|
||||
#undef HAVE_SYS_SEM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/sockio.h> header file. */
|
||||
#undef HAVE_SYS_SOCKIO_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/uio.h> header file. */
|
||||
#undef HAVE_SYS_UIO_H
|
||||
|
||||
/* Define to 1 if you have the <sys/un.h> header file. */
|
||||
#undef HAVE_SYS_UN_H
|
||||
|
||||
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
|
||||
#undef HAVE_SYS_WAIT_H
|
||||
|
||||
/* Define to 1 if you have the <time.h> header file. */
|
||||
#undef HAVE_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#undef HAVE_VFORK
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
#undef HAVE_VFORK_H
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
#undef HAVE_WORKING_FORK
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#undef HAVE_WORKING_VFORK
|
||||
|
||||
/* localstate directory */
|
||||
#undef LOCALSTATEDIR
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Shared memory define for Darwin platform */
|
||||
#undef MAP_ANONYMOUS
|
||||
|
||||
/* Number of chars in a file name */
|
||||
#undef NAME_MAX
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
#undef NO_MINUS_C_MINUS_O
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* quarterback built-in features */
|
||||
#undef PACKAGE_FEATURES
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Number of chars in a path name including nul */
|
||||
#undef PATH_MAX
|
||||
|
||||
/* alpha */
|
||||
#undef QB_ARCH_ALPHA
|
||||
|
||||
/* arm */
|
||||
#undef QB_ARCH_ARM
|
||||
|
||||
/* ia64 */
|
||||
#undef QB_ARCH_IA64
|
||||
|
||||
/* mips */
|
||||
#undef QB_ARCH_MIPS
|
||||
|
||||
/* powerpc */
|
||||
#undef QB_ARCH_POWERPC
|
||||
|
||||
/* sparc */
|
||||
#undef QB_ARCH_SPARC
|
||||
|
||||
/* need atomic memory barrier */
|
||||
#undef QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED
|
||||
|
||||
/* Compiling for BSD platform */
|
||||
#undef QB_BSD
|
||||
|
||||
/* Compiling for Darwin platform */
|
||||
#undef QB_DARWIN
|
||||
|
||||
/* shared and fixed mmap must align on 16k */
|
||||
#undef QB_FORCE_SHM_ALIGN
|
||||
|
||||
/* Compiling for FreeBSD >= 8 platform */
|
||||
#undef QB_FREEBSD_GE_8
|
||||
|
||||
/* Enabling code using __attribute__((section)) */
|
||||
#undef QB_HAVE_ATTRIBUTE_SECTION
|
||||
|
||||
/* Compiling for Linux platform */
|
||||
#undef QB_LINUX
|
||||
|
||||
/* Compiling for Solaris platform */
|
||||
#undef QB_SOLARIS
|
||||
|
||||
/* Socket directory */
|
||||
#undef SOCKETDIR
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Prevent being scheduled RR */
|
||||
#undef TS_CLASS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* The semun structure is undefined */
|
||||
#undef _SEM_SEMUN_UNDEFINED
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
#undef _UINT32_T
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
#undef _UINT64_T
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
#undef _UINT8_T
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef gid_t
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 32 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef int32_t
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 64 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef int64_t
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 8 bits if such
|
||||
a type exists and the standard includes do not define it. */
|
||||
#undef int8_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef mode_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef ssize_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef uid_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 32 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint32_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 64 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint64_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 8 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint8_t
|
||||
|
||||
/* Define as `fork' if `vfork' does not work. */
|
||||
#undef vfork
|
||||
140
include/os_base.h
Normal file
140
include/os_base.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QB_OS_BASE_H_DEFINED
|
||||
#define QB_OS_BASE_H_DEFINED
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1
|
||||
#endif /* _GNU_SOURCE */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif /* HAVE_SYS_TYPES_H */
|
||||
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif /* HAVE_SYS_UIO_H */
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif /* HAVE_STDINT_H */
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif /* HAVE_STDLIB_H */
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif /* HAVE_STRING_H */
|
||||
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif /* HAVE_STRINGS_H */
|
||||
|
||||
#ifndef S_SPLINT_S
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#endif /* S_SPLINT_S */
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif /*HAVE_ERRNO_H*/
|
||||
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif /* HAVE_TIME_H */
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif /* HAVE_SYS_TIME_H */
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif /* HAVE_SYS_STAT_H */
|
||||
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif /* HAVE_FCNTL_H */
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif /* HAVE_SYS_SOCKET_H */
|
||||
|
||||
#ifndef S_SPLINT_S
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
#include <syslog.h>
|
||||
#endif /* HAVE_SYSLOG_H */
|
||||
#endif /* S_SPLINT_S */
|
||||
|
||||
#if defined HAVE_CLOCK_GETTIME && defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
|
||||
#define HAVE_MONOTONIC_CLOCK 1
|
||||
#endif /* have monotonic clock */
|
||||
|
||||
#ifdef HAVE_EPOLL_CREATE1
|
||||
#define HAVE_EPOLL 1
|
||||
#endif /* HAVE_EPOLL_CREATE */
|
||||
|
||||
/*
|
||||
* Darwin claims to support process shared synchronization
|
||||
* but it really does not. The unistd.h header file is wrong.
|
||||
*/
|
||||
#if defined(DISABLE_POSIX_THREAD_PROCESS_SHARED) || defined(__UCLIBC__)
|
||||
#undef HAVE_POSIX_SHARED_SEMAPHORE
|
||||
#undef HAVE_PTHREAD_SHARED_SPIN_LOCK
|
||||
#else
|
||||
#if _POSIX_THREAD_PROCESS_SHARED > 0
|
||||
#define HAVE_POSIX_SHARED_SEMAPHORE 1
|
||||
|
||||
#if defined(HAVE_PTHREAD_SPIN_LOCK)
|
||||
#define HAVE_PTHREAD_SHARED_SPIN_LOCK 1
|
||||
#endif /* HAVE_PTHREAD_SPIN_LOCK */
|
||||
|
||||
#endif /* _POSIX_THREAD_PROCESS_SHARED */
|
||||
#endif /* DISABLE_POSIX_THREAD_PROCESS_SHARED */
|
||||
|
||||
#ifndef HAVE_STRCHRNUL
|
||||
char *strchrnul (const char *s, int c_in);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
size_t strlcpy(char *dest, const char *src, size_t maxlen);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCAT
|
||||
size_t strlcat(char *dest, const char *src, size_t maxlen);
|
||||
#endif
|
||||
|
||||
#endif /* QB_OS_BASE_H_DEFINED */
|
||||
26
include/qb/Makefile.am
Normal file
26
include/qb/Makefile.am
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright (c) 2010 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Angus Salkeld <asalkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
instdir = $(includedir)/qb/
|
||||
inst_HEADERS = qbhdb.h qblist.h qbdefs.h qbatomic.h \
|
||||
qbloop.h qbrb.h qbutil.h qbarray.h \
|
||||
qbipcc.h qbipcs.h qbipc_common.h qblog.h \
|
||||
qbconfig.h qbmap.h
|
||||
529
include/qb/Makefile.in
Normal file
529
include/qb/Makefile.in
Normal file
@ -0,0 +1,529 @@
|
||||
# Makefile.in generated by automake 1.11.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# Copyright (c) 2010 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Angus Salkeld <asalkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = include/qb
|
||||
DIST_COMMON = $(inst_HEADERS) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in $(srcdir)/qbconfig.h.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/include/config.h qbconfig.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(instdir)"
|
||||
HEADERS = $(inst_HEADERS)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CHECK_CFLAGS = @CHECK_CFLAGS@
|
||||
CHECK_LIBS = @CHECK_LIBS@
|
||||
CP = @CP@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DOXYGEN = @DOXYGEN@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GLIB_CFLAGS = @GLIB_CFLAGS@
|
||||
GLIB_LIBS = @GLIB_LIBS@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIB_RT = @LIB_RT@
|
||||
LINT_FLAGS = @LINT_FLAGS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKGCONFIG = @PKGCONFIG@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
SOCKETDIR = @SOCKETDIR@
|
||||
SPLINT = @SPLINT@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
instdir = $(includedir)/qb/
|
||||
inst_HEADERS = qbhdb.h qblist.h qbdefs.h qbatomic.h \
|
||||
qbloop.h qbrb.h qbutil.h qbarray.h \
|
||||
qbipcc.h qbipcs.h qbipc_common.h qblog.h \
|
||||
qbconfig.h qbmap.h
|
||||
|
||||
all: qbconfig.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-am
|
||||
|
||||
.SUFFIXES:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/qb/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu include/qb/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
qbconfig.h: stamp-h2
|
||||
@if test ! -f $@; then rm -f stamp-h2; else :; fi
|
||||
@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h2; else :; fi
|
||||
|
||||
stamp-h2: $(srcdir)/qbconfig.h.in $(top_builddir)/config.status
|
||||
@rm -f stamp-h2
|
||||
cd $(top_builddir) && $(SHELL) ./config.status include/qb/qbconfig.h
|
||||
$(srcdir)/qbconfig.h.in: $(am__configure_deps)
|
||||
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
|
||||
rm -f stamp-h2
|
||||
touch $@
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f qbconfig.h stamp-h2
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
install-instHEADERS: $(inst_HEADERS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(instdir)" || $(MKDIR_P) "$(DESTDIR)$(instdir)"
|
||||
@list='$(inst_HEADERS)'; test -n "$(instdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(instdir)'"; \
|
||||
$(INSTALL_HEADER) $$files "$(DESTDIR)$(instdir)" || exit $$?; \
|
||||
done
|
||||
|
||||
uninstall-instHEADERS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(inst_HEADERS)'; test -n "$(instdir)" || list=; \
|
||||
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
|
||||
dir='$(DESTDIR)$(instdir)'; $(am__uninstall_files_from_dir)
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) qbconfig.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) qbconfig.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) qbconfig.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) qbconfig.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(HEADERS) qbconfig.h
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(instdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-instHEADERS
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-instHEADERS
|
||||
|
||||
.MAKE: all install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool ctags distclean distclean-generic distclean-hdr \
|
||||
distclean-libtool distclean-tags distdir dvi dvi-am html \
|
||||
html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-instHEADERS install-man install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-generic \
|
||||
mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
|
||||
uninstall-am uninstall-instHEADERS
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
120
include/qb/qbarray.h
Normal file
120
include/qb/qbarray.h
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QB_ARRAY_H_DEFINED
|
||||
#define QB_ARRAY_H_DEFINED
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef S_SPLINT_S
|
||||
#include <unistd.h>
|
||||
#endif /* S_SPLINT_S */
|
||||
#include <qb/qbdefs.h>
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/**
|
||||
* @file qbarray.h
|
||||
* This is a dynamic array (it can grow, but without moving memory).
|
||||
*
|
||||
* @code
|
||||
* arr = qb_array_create_2(64, sizeof(struct my_struct), 256);
|
||||
* ...
|
||||
* res = qb_array_index(arr, idx, (void**)&my_ptr);
|
||||
* if (res < 0) {
|
||||
* return res;
|
||||
* }
|
||||
* // use my_ptr, now even if there is a grow, this pointer will be valid.
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
struct qb_array;
|
||||
|
||||
/**
|
||||
* This is an opaque data type representing an instance of an array.
|
||||
*/
|
||||
typedef struct qb_array qb_array_t;
|
||||
|
||||
/**
|
||||
* Create an array with fixed sized elements.
|
||||
*
|
||||
* @param max_elements initial max elements.
|
||||
* @param element_size size of each element.
|
||||
* @return array instance.
|
||||
*/
|
||||
qb_array_t* qb_array_create(size_t max_elements, size_t element_size);
|
||||
|
||||
/**
|
||||
* Create an array with fixed sized elements.
|
||||
*
|
||||
* @param max_elements initial max elements.
|
||||
* @param element_size size of each element.
|
||||
* @param autogrow_elements the number of elements to grow automatically by.
|
||||
*
|
||||
* @return array instance.
|
||||
*/
|
||||
qb_array_t* qb_array_create_2(size_t max_elements, size_t element_size,
|
||||
size_t autogrow_elements);
|
||||
|
||||
|
||||
/**
|
||||
* Get an element at a particular index.
|
||||
* @param a array instance.
|
||||
* @param idx the index
|
||||
* @param element_out the pointer to the element data.
|
||||
* @return (0 == success, else -errno)
|
||||
*/
|
||||
int32_t qb_array_index(qb_array_t* a, int32_t idx, void** element_out);
|
||||
|
||||
/**
|
||||
* Grow the array.
|
||||
*
|
||||
* @param a array instance.
|
||||
* @param max_elements the new maximum size of the array.
|
||||
* @return (0 == success, else -errno)
|
||||
*/
|
||||
int32_t qb_array_grow(qb_array_t* a, size_t max_elements);
|
||||
|
||||
/**
|
||||
* Get the number of bins used or the array.
|
||||
*/
|
||||
size_t qb_array_num_bins_get(qb_array_t* a);
|
||||
|
||||
/**
|
||||
* Get the number of elements per bin.
|
||||
*/
|
||||
size_t qb_array_elems_per_bin_get(qb_array_t* a);
|
||||
|
||||
/**
|
||||
* Free all the memory used by the array.
|
||||
* @param a array instance.
|
||||
*/
|
||||
void qb_array_free(qb_array_t * a);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* QB_ARRAY_H_DEFINED */
|
||||
207
include/qb/qbatomic.h
Normal file
207
include/qb/qbatomic.h
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Sebastian Wilhelmi
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copied from the glib code base (glib/gatomic.h) and namespaced
|
||||
* for libqb.
|
||||
*/
|
||||
|
||||
#ifndef QB_ATOMIC_H_DEFINED
|
||||
#define QB_ATOMIC_H_DEFINED
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbconfig.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Basic atomic integer and pointer operations
|
||||
*
|
||||
* The following functions can be used to atomically access integers and
|
||||
* pointers. They are implemented as inline assembler function on most
|
||||
* platforms and use slower fall-backs otherwise. Using them can sometimes
|
||||
* save you from using a performance-expensive pthread_mutex to protect the
|
||||
* integer or pointer.
|
||||
*
|
||||
* The most important usage is reference counting. Using
|
||||
* qb_atomic_int_inc() and qb_atomic_int_dec_and_test() makes reference
|
||||
* counting a very fast operation.
|
||||
*
|
||||
* You must not directly read integers or pointers concurrently
|
||||
* accessed by multiple threads, but use the atomic accessor functions
|
||||
* instead. That is, always use qb_atomic_int_get() and qb_atomic_pointer_get()
|
||||
* for read outs. They provide the neccessary synchonization mechanisms
|
||||
* like memory barriers to access memory locations concurrently.
|
||||
*
|
||||
* If you are using those functions for anything apart from
|
||||
* simple reference counting, you should really be aware of the implications
|
||||
* of doing that. There are literally thousands of ways to shoot yourself
|
||||
* in the foot. So if in doubt, use a pthread_mutex. If you don't know, what
|
||||
* memory barriers are, do not use anything but qb_atomic_int_inc() and
|
||||
* qb_atomic_int_dec_and_test().
|
||||
*
|
||||
* It is not safe to set an integer or pointer just by assigning
|
||||
* to it, when it is concurrently accessed by other threads with the following
|
||||
* functions. Use qb_atomic_int_compare_and_exchange() or
|
||||
* qb_atomic_pointer_compare_and_exchange() respectively.
|
||||
*/
|
||||
|
||||
void qb_atomic_init(void);
|
||||
|
||||
/**
|
||||
* Atomically adds val to the integer pointed to by atomic.
|
||||
* It returns the value of *atomic just before the addition
|
||||
* took place. Also acts as a memory barrier.
|
||||
*
|
||||
* @param atomic a pointer to an integer
|
||||
* @param val the value to add to *atomic
|
||||
* @return the value of *atomic before the addition.
|
||||
*/
|
||||
int32_t qb_atomic_int_exchange_and_add(volatile int32_t QB_GNUC_MAY_ALIAS *
|
||||
atomic, int32_t val);
|
||||
/**
|
||||
* Atomically adds val to the integer pointed to by atomic.
|
||||
* Also acts as a memory barrier.
|
||||
*
|
||||
* @param atomic a pointer to an integer
|
||||
* @param val the value to add to *atomic
|
||||
*/
|
||||
void qb_atomic_int_add(volatile int32_t QB_GNUC_MAY_ALIAS * atomic, int32_t val);
|
||||
|
||||
/**
|
||||
* Compares oldval with the integer pointed to by atomic and
|
||||
* if they are equal, atomically exchanges *atomic with newval.
|
||||
* Also acts as a memory barrier.
|
||||
*
|
||||
* @param atomic a pointer to an integer
|
||||
* @param oldval the assumed old value of *atomic
|
||||
* @param newval the new value of *atomic
|
||||
*
|
||||
* @return QB_TRUE, if *atomic was equal oldval. QB_FALSE otherwise.
|
||||
*/
|
||||
int32_t qb_atomic_int_compare_and_exchange(volatile int32_t QB_GNUC_MAY_ALIAS *
|
||||
atomic, int32_t oldval,
|
||||
int32_t newval);
|
||||
|
||||
/**
|
||||
* Compares oldval with the pointer pointed to by atomic and
|
||||
* if they are equal, atomically exchanges *atomic with newval.
|
||||
* Also acts as a memory barrier.
|
||||
*
|
||||
* @param atomic a pointer to a void*
|
||||
* @param oldval the assumed old value of *atomic
|
||||
* @param newval the new value of *atomic
|
||||
*
|
||||
* @return QB_TRUE if atomic was equal oldval, else QB_FALSE.
|
||||
*/
|
||||
int32_t qb_atomic_pointer_compare_and_exchange(volatile void* QB_GNUC_MAY_ALIAS
|
||||
* atomic, void* oldval,
|
||||
void* newval);
|
||||
|
||||
/**
|
||||
* Reads the value of the integer pointed to by atomic.
|
||||
* Also acts as a memory barrier.
|
||||
*
|
||||
* @param atomic a pointer to an integer
|
||||
*
|
||||
* @return the value of atomic
|
||||
*/
|
||||
int32_t qb_atomic_int_get(volatile int32_t QB_GNUC_MAY_ALIAS * atomic);
|
||||
|
||||
/**
|
||||
* Sets the value of the integer pointed to by atomic.
|
||||
* Also acts as a memory barrier.
|
||||
*
|
||||
* @param atomic a pointer to an integer
|
||||
* @param newval the new value
|
||||
*/
|
||||
void qb_atomic_int_set(volatile int32_t QB_GNUC_MAY_ALIAS * atomic,
|
||||
int32_t newval);
|
||||
|
||||
/**
|
||||
* Reads the value of the pointer pointed to by atomic.
|
||||
* Also acts as a memory barrier.
|
||||
*
|
||||
* @param atomic a pointer to a void*.
|
||||
* @return the value to add to atomic.
|
||||
*/
|
||||
void* qb_atomic_pointer_get(volatile void* QB_GNUC_MAY_ALIAS * atomic);
|
||||
|
||||
/**
|
||||
* Sets the value of the pointer pointed to by atomic.
|
||||
* Also acts as a memory barrier.
|
||||
*
|
||||
* @param atomic a pointer to a void*
|
||||
* @param newval the new value
|
||||
*
|
||||
*/
|
||||
void qb_atomic_pointer_set(volatile void* QB_GNUC_MAY_ALIAS * atomic,
|
||||
void* newval);
|
||||
|
||||
#ifndef QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED
|
||||
#define qb_atomic_int_get(atomic) ((int32_t)*(atomic))
|
||||
#define qb_atomic_int_set(atomic, newval) ((void) (*(atomic) = (newval)))
|
||||
#define qb_atomic_pointer_get(atomic) ((void*)*(atomic))
|
||||
#define qb_atomic_pointer_set(atomic, newval) ((void*) (*(atomic) = (newval)))
|
||||
#else
|
||||
#define qb_atomic_int_get(atomic) \
|
||||
((void) sizeof (char* [sizeof (*(atomic)) == sizeof (int32_t) ? 1 : -1]), \
|
||||
(qb_atomic_int_get) ((volatile int32_t QB_GNUC_MAY_ALIAS *) (volatile void *) (atomic)))
|
||||
#define qb_atomic_int_set(atomic, newval) \
|
||||
((void) sizeof (char* [sizeof (*(atomic)) == sizeof (int32_t) ? 1 : -1]), \
|
||||
(qb_atomic_int_set) ((volatile int32_t QB_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval)))
|
||||
#define qb_atomic_pointer_get(atomic) \
|
||||
((void) sizeof (char* [sizeof (*(atomic)) == sizeof (void*) ? 1 : -1]), \
|
||||
(qb_atomic_pointer_get) ((volatile void* QB_GNUC_MAY_ALIAS *) (volatile void *) (atomic)))
|
||||
#define qb_atomic_pointer_set(atomic, newval) \
|
||||
((void) sizeof (char* [sizeof (*(atomic)) == sizeof (void*) ? 1 : -1]), \
|
||||
(qb_atomic_pointer_set) ((volatile void* QB_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval)))
|
||||
#endif /* QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
|
||||
|
||||
/**
|
||||
* Atomically increments the integer pointed to by atomic by 1.
|
||||
*
|
||||
* @param atomic a pointer to an integer.
|
||||
*/
|
||||
#define qb_atomic_int_inc(atomic) (qb_atomic_int_add ((atomic), 1))
|
||||
|
||||
/**
|
||||
* Atomically decrements the integer pointed to by atomic by 1.
|
||||
*
|
||||
* @param atomic a pointer to an integer
|
||||
*
|
||||
* @return QB_TRUE if the integer pointed to by atomic is 0
|
||||
* after decrementing it
|
||||
*/
|
||||
#define qb_atomic_int_dec_and_test(atomic) \
|
||||
(qb_atomic_int_exchange_and_add ((atomic), -1) == 1)
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* QB_ATOMIC_H_DEFINED */
|
||||
32
include/qb/qbconfig.h
Normal file
32
include/qb/qbconfig.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* include/qb/qbconfig.h. Generated from qbconfig.h.in by configure. */
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QB_CONFIG_H_DEFINED
|
||||
#define QB_CONFIG_H_DEFINED
|
||||
|
||||
/* need atomic memory barrier */
|
||||
#define QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED 1
|
||||
|
||||
/* Enabling code using __attribute__((section)) */
|
||||
#define QB_HAVE_ATTRIBUTE_SECTION 1
|
||||
|
||||
#endif /* QB_CONFIG_H_DEFINED */
|
||||
31
include/qb/qbconfig.h.in
Normal file
31
include/qb/qbconfig.h.in
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QB_CONFIG_H_DEFINED
|
||||
#define QB_CONFIG_H_DEFINED
|
||||
|
||||
/* need atomic memory barrier */
|
||||
#undef QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED
|
||||
|
||||
/* Enabling code using __attribute__((section)) */
|
||||
#undef QB_HAVE_ATTRIBUTE_SECTION
|
||||
|
||||
#endif /* QB_CONFIG_H_DEFINED */
|
||||
108
include/qb/qbdefs.h
Normal file
108
include/qb/qbdefs.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QB_DEFS_H_DEFINED
|
||||
#define QB_DEFS_H_DEFINED
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/**
|
||||
* @file qbdefs.h
|
||||
* @author Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* These are some convience macros and defines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* simple math macros
|
||||
*/
|
||||
#define QB_ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
|
||||
#define QB_ABS(i) (((i) < 0) ? -(i) : (i))
|
||||
#define QB_MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define QB_MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
/*
|
||||
* the usual boolean defines
|
||||
*/
|
||||
#define QB_FALSE 0
|
||||
#define QB_TRUE (!QB_FALSE)
|
||||
|
||||
/*
|
||||
* bit manipulation
|
||||
*/
|
||||
#define qb_bit_value(bit) (1 << (bit))
|
||||
#define qb_bit_set(barray, bit) (barray |= qb_bit_value(bit))
|
||||
#define qb_bit_clear(barray, bit) (barray &= ~(qb_bit_value(bit)))
|
||||
#define qb_bit_is_set(barray, bit) (barray & qb_bit_value(bit))
|
||||
#define qb_bit_is_clear(barray, bit) (!(barray & qb_bit_value(bit)))
|
||||
|
||||
|
||||
/*
|
||||
* handy time based converters.
|
||||
*/
|
||||
#ifndef HZ
|
||||
#define HZ 100 /* 10ms */
|
||||
#endif
|
||||
|
||||
#define QB_TIME_MS_IN_SEC 1000ULL
|
||||
#define QB_TIME_US_IN_SEC 1000000ULL
|
||||
#define QB_TIME_NS_IN_SEC 1000000000ULL
|
||||
#define QB_TIME_US_IN_MSEC 1000ULL
|
||||
#define QB_TIME_NS_IN_MSEC 1000000ULL
|
||||
#define QB_TIME_NS_IN_USEC 1000ULL
|
||||
|
||||
|
||||
#if defined (__GNUC__) && defined (__STRICT_ANSI__)
|
||||
#undef inline
|
||||
#define inline __inline__
|
||||
#undef typeof
|
||||
#define typeof __typeof__
|
||||
#endif /* ANSI */
|
||||
|
||||
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
|
||||
#define QB_GNUC_DEPRECATED \
|
||||
__attribute__((__deprecated__))
|
||||
#else
|
||||
#define QB_GNUC_DEPRECATED
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
||||
#define QB_GNUC_DEPRECATED_FOR(f) \
|
||||
__attribute__((deprecated("Use " #f " instead")))
|
||||
#else
|
||||
#define QB_GNUC_DEPRECATED_FOR(f) QB_GNUC_DEPRECATED
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
|
||||
#define QB_GNUC_MAY_ALIAS __attribute__((may_alias))
|
||||
#else
|
||||
#define QB_GNUC_MAY_ALIAS
|
||||
#endif
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* QB_DEFS_H_DEFINED */
|
||||
178
include/qb/qbhdb.h
Normal file
178
include/qb/qbhdb.h
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Steven Dake <sdake@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QB_HDB_H_DEFINED
|
||||
#define QB_HDB_H_DEFINED
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <qb/qbarray.h>
|
||||
|
||||
/**
|
||||
* @file qbhdb.h
|
||||
* The handle database is for reference counting objects.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generic handle type is 64 bits.
|
||||
*/
|
||||
typedef uint64_t qb_handle_t;
|
||||
|
||||
/*
|
||||
* Formatting for string printing on 32/64 bit systems
|
||||
*/
|
||||
#define QB_HDB_D_FORMAT "%"PRIu64
|
||||
#define QB_HDB_X_FORMAT "%"PRIx64
|
||||
|
||||
struct qb_hdb_handle {
|
||||
int32_t state;
|
||||
void *instance;
|
||||
int32_t check;
|
||||
int32_t ref_count;
|
||||
};
|
||||
|
||||
struct qb_hdb {
|
||||
uint32_t handle_count;
|
||||
qb_array_t *handles;
|
||||
uint32_t iterator;
|
||||
void (*destructor) (void *);
|
||||
uint32_t first_run;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convience macro for declaring a file scoped handle database.
|
||||
* @code
|
||||
* QB_HDB_DECLARE(my_handle_database, NULL);
|
||||
* @endcode
|
||||
*/
|
||||
#define QB_HDB_DECLARE(database_name,destructor_function) \
|
||||
static struct qb_hdb (database_name) = { \
|
||||
.handle_count = 0, \
|
||||
.handles = NULL, \
|
||||
.iterator = 0, \
|
||||
.destructor = destructor_function, \
|
||||
.first_run = 1 \
|
||||
}; \
|
||||
|
||||
/**
|
||||
* Create a new database.
|
||||
* @param hdb the database to init.
|
||||
*/
|
||||
void qb_hdb_create(struct qb_hdb *hdb);
|
||||
|
||||
/**
|
||||
* Destroy a handle database.
|
||||
* @param hdb the database to destroy.
|
||||
*/
|
||||
void qb_hdb_destroy(struct qb_hdb *hdb);
|
||||
|
||||
/**
|
||||
* Create a new handle.
|
||||
* @param hdb the database instance
|
||||
* @param instance_size size of the object to malloc
|
||||
* @param handle_id_out new handle
|
||||
* @return (0 == ok, -errno faliure)
|
||||
*/
|
||||
int32_t qb_hdb_handle_create(struct qb_hdb *hdb, int32_t instance_size,
|
||||
qb_handle_t * handle_id_out);
|
||||
/**
|
||||
* Get the instance associated with this handle and increase it's refcount.
|
||||
* @param handle_in the handle
|
||||
* @param hdb the database instance
|
||||
* @param instance (out) pointer to the desired object.
|
||||
* @return (0 == ok, -errno faliure)
|
||||
*/
|
||||
int32_t qb_hdb_handle_get(struct qb_hdb *hdb, qb_handle_t handle_in,
|
||||
void **instance);
|
||||
/**
|
||||
* Get the instance associated with this handle and increase it's refcount.
|
||||
* @param handle_in the handle
|
||||
* @param hdb the database instance
|
||||
* @param instance (out) pointer to the desired object.
|
||||
* @return (0 == ok, -errno faliure)
|
||||
*/
|
||||
int32_t qb_hdb_handle_get_always(struct qb_hdb *hdb, qb_handle_t handle_in,
|
||||
void **instance);
|
||||
/**
|
||||
* Put the instance associated with this handle and decrease it's refcount.
|
||||
* @param handle_in the handle
|
||||
* @param hdb the database instance
|
||||
* @return (0 == ok, -errno faliure)
|
||||
*/
|
||||
int32_t qb_hdb_handle_put(struct qb_hdb *hdb, qb_handle_t handle_in);
|
||||
|
||||
/**
|
||||
* Request the destruction of the object.
|
||||
*
|
||||
* When the refcount is 0, it will be destroyed.
|
||||
*
|
||||
* @param handle_in the handle
|
||||
* @param hdb the database instance
|
||||
* @return (0 == ok, -errno faliure)
|
||||
*/
|
||||
int32_t qb_hdb_handle_destroy(struct qb_hdb *hdb, qb_handle_t handle_in);
|
||||
|
||||
/**
|
||||
* Get the current refcount.
|
||||
* @param handle_in the handle
|
||||
* @param hdb the database instance
|
||||
* @return (>= 0 is the refcount, -errno faliure)
|
||||
*/
|
||||
int32_t qb_hdb_handle_refcount_get(struct qb_hdb *hdb, qb_handle_t handle_in);
|
||||
|
||||
/**
|
||||
* Reset the iterator.
|
||||
* @param hdb the database instance
|
||||
*/
|
||||
void qb_hdb_iterator_reset(struct qb_hdb *hdb);
|
||||
|
||||
/**
|
||||
* Get the next object and increament it's refcount.
|
||||
*
|
||||
* Remember to call qb_hdb_handle_put()
|
||||
*
|
||||
* @param hdb the database instance
|
||||
* @param handle (out) the handle
|
||||
* @param instance (out) pointer to the desired object.
|
||||
* @return (0 == ok, -errno faliure)
|
||||
*/
|
||||
int32_t qb_hdb_iterator_next(struct qb_hdb *hdb, void **instance,
|
||||
qb_handle_t * handle);
|
||||
|
||||
uint32_t qb_hdb_base_convert(qb_handle_t handle);
|
||||
uint64_t qb_hdb_nocheck_convert(uint32_t handle);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
#endif /* QB_HDB_H_DEFINED */
|
||||
65
include/qb/qbipc_common.h
Normal file
65
include/qb/qbipc_common.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QB_IPC_COMMON_H_DEFINED
|
||||
#define QB_IPC_COMMON_H_DEFINED
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
struct qb_ipc_request_header {
|
||||
int32_t id __attribute__ ((aligned(8)));
|
||||
int32_t size __attribute__ ((aligned(8)));
|
||||
} __attribute__ ((aligned(8)));
|
||||
|
||||
struct qb_ipc_response_header {
|
||||
int32_t id __attribute__ ((aligned(8)));
|
||||
int32_t size __attribute__ ((aligned(8)));
|
||||
int32_t error __attribute__ ((aligned(8)));
|
||||
} __attribute__ ((aligned(8)));
|
||||
|
||||
enum qb_ipc_type {
|
||||
QB_IPC_SOCKET,
|
||||
QB_IPC_SHM,
|
||||
QB_IPC_POSIX_MQ,
|
||||
QB_IPC_SYSV_MQ,
|
||||
};
|
||||
|
||||
|
||||
#define QB_IPC_MSG_NEW_MESSAGE 0
|
||||
#define QB_IPC_MSG_USER_START QB_IPC_MSG_NEW_MESSAGE
|
||||
#define QB_IPC_MSG_AUTHENTICATE -1
|
||||
#define QB_IPC_MSG_NEW_EVENT_SOCK -2
|
||||
#define QB_IPC_MSG_DISCONNECT -3
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* QB_IPC_COMMON_H_DEFINED */
|
||||
190
include/qb/qbipcc.h
Normal file
190
include/qb/qbipcc.h
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2007, 2009 Red Hat, Inc.
|
||||
*
|
||||
* Author: Steven Dake <sdake@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QB_IPCC_H_DEFINED
|
||||
#define QB_IPCC_H_DEFINED
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include <qb/qbconfig.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <qb/qbhdb.h>
|
||||
#include <qb/qbipc_common.h>
|
||||
|
||||
/**
|
||||
* @file qbipcc.h
|
||||
*
|
||||
* Client IPC API.
|
||||
*
|
||||
* @par Lifecycle of an IPC connection.
|
||||
* An IPC connection is made to the server with qb_ipcc_connect(). This function
|
||||
* connects to the server and requests channels be created for communication.
|
||||
* To disconnect, the client either exits or executes the function qb_ipcc_disconnect().
|
||||
*
|
||||
* @par Synchronous communication
|
||||
* The function qb_ipcc_sendv_recv() sends an iovector request and receives a response.
|
||||
*
|
||||
* @par Asynchronous requests from the client
|
||||
* The function qb_ipcc_sendv() sends an iovector request.
|
||||
* The function qb_ipcc_send() sends an message buffer request.
|
||||
*
|
||||
* @par Asynchronous events from the server
|
||||
* The qb_ipcc_event_recv() function receives an out-of-band asyncronous message.
|
||||
* The asynchronous messages are queued and can provide very high out-of-band performance.
|
||||
* To determine when to call qb_ipcc_event_recv() the qb_ipcc_fd_get() call is
|
||||
* used to obtain a file descriptor used in the poll() or select() system calls.
|
||||
*
|
||||
* @example ipcclient.c
|
||||
* This is an example of how to use the client.
|
||||
*/
|
||||
|
||||
typedef struct qb_ipcc_connection qb_ipcc_connection_t;
|
||||
|
||||
/**
|
||||
* Create a connection to an IPC service.
|
||||
*
|
||||
* @param name name of the service.
|
||||
* @param max_msg_size biggest msg size.
|
||||
* @return NULL (error: see errno) or a connection object.
|
||||
*/
|
||||
qb_ipcc_connection_t*
|
||||
qb_ipcc_connect(const char *name, size_t max_msg_size);
|
||||
|
||||
/**
|
||||
* Disconnect an IPC connection.
|
||||
*
|
||||
* @param c connection instance
|
||||
*/
|
||||
void qb_ipcc_disconnect(qb_ipcc_connection_t* c);
|
||||
|
||||
/**
|
||||
* Get the file descriptor to poll.
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param fd (out) file descriptor to poll
|
||||
*/
|
||||
int32_t qb_ipcc_fd_get(qb_ipcc_connection_t* c, int32_t * fd);
|
||||
|
||||
/**
|
||||
* Set the maximum allowable flowcontrol value.
|
||||
*
|
||||
* @note the default is 1
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param max the max allowable flowcontrol value (1 or 2)
|
||||
*/
|
||||
int32_t qb_ipcc_fc_enable_max_set(qb_ipcc_connection_t * c, uint32_t max);
|
||||
|
||||
/**
|
||||
* Send a message.
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param msg_ptr pointer to a message to send
|
||||
* @param msg_len the size of the message
|
||||
* @return (size sent, -errno == error)
|
||||
*/
|
||||
ssize_t qb_ipcc_send(qb_ipcc_connection_t* c, const void *msg_ptr,
|
||||
size_t msg_len);
|
||||
/**
|
||||
* Send a message (iovec).
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param iov pointer to an iovec struct to send
|
||||
* @param iov_len the number of iovecs used
|
||||
* @return (size sent, -errno == error)
|
||||
*/
|
||||
ssize_t qb_ipcc_sendv(qb_ipcc_connection_t* c, const struct iovec* iov,
|
||||
size_t iov_len);
|
||||
/**
|
||||
* Receive a response.
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param msg_ptr pointer to a message buffer to receive into
|
||||
* @param msg_len the size of the buffer
|
||||
* @param ms_timeout max time to wait for a response
|
||||
* @return (size recv'ed, -errno == error)
|
||||
*/
|
||||
ssize_t qb_ipcc_recv(qb_ipcc_connection_t* c, void *msg_ptr,
|
||||
size_t msg_len, int32_t ms_timeout);
|
||||
|
||||
/**
|
||||
* This is a convenience function that simply sends and then recvs.
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param iov pointer to an iovec struct to send
|
||||
* @param iov_len the number of iovecs used
|
||||
* @param msg_ptr pointer to a message buffer to receive into
|
||||
* @param msg_len the size of the buffer
|
||||
* @param ms_timeout max time to wait for a response
|
||||
*
|
||||
* @see qb_ipcc_sendv() qb_ipcc_recv()
|
||||
*/
|
||||
ssize_t qb_ipcc_sendv_recv(qb_ipcc_connection_t *c,
|
||||
const struct iovec *iov, uint32_t iov_len,
|
||||
void *msg_ptr, size_t msg_len,
|
||||
int32_t ms_timeout);
|
||||
|
||||
/**
|
||||
* Receive an event.
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param msg_ptr pointer to a message buffer to receive into
|
||||
* @param msg_len the size of the buffer
|
||||
* @param ms_timeout time in milli seconds to wait for a message
|
||||
* 0 == no wait, negative == block, positive == wait X ms.
|
||||
* @param ms_timeout max time to wait for a response
|
||||
* @return size of the message or error (-errno)
|
||||
*/
|
||||
ssize_t qb_ipcc_event_recv(qb_ipcc_connection_t* c, void *msg_ptr,
|
||||
size_t msg_len, int32_t ms_timeout);
|
||||
|
||||
/**
|
||||
* Associate a "user" pointer with this connection.
|
||||
*
|
||||
* @param context the point to associate with this connection.
|
||||
* @param c connection instance
|
||||
* @see qb_ipcc_context_get()
|
||||
*/
|
||||
void qb_ipcc_context_set(qb_ipcc_connection_t *c, void *context);
|
||||
|
||||
/**
|
||||
* Get the context (set previously)
|
||||
*
|
||||
* @param c connection instance
|
||||
* @return the context
|
||||
* @see qb_ipcc_context_set()
|
||||
*/
|
||||
void *qb_ipcc_context_get(qb_ipcc_connection_t *c);
|
||||
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* QB_IPCC_H_DEFINED */
|
||||
342
include/qb/qbipcs.h
Normal file
342
include/qb/qbipcs.h
Normal file
@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2009 Red Hat, Inc.
|
||||
*
|
||||
* Author: Steven Dake <sdake@redhat.com>,
|
||||
* Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QB_IPCS_H_DEFINED
|
||||
#define QB_IPCS_H_DEFINED
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/uio.h>
|
||||
#include <qb/qbipc_common.h>
|
||||
#include <qb/qbhdb.h>
|
||||
#include <qb/qbloop.h>
|
||||
|
||||
/**
|
||||
* @file qbipcs.h
|
||||
*
|
||||
* Server IPC API.
|
||||
*
|
||||
* @example ipcserver.c
|
||||
*/
|
||||
|
||||
enum qb_ipcs_rate_limit {
|
||||
QB_IPCS_RATE_FAST,
|
||||
QB_IPCS_RATE_NORMAL,
|
||||
QB_IPCS_RATE_SLOW,
|
||||
QB_IPCS_RATE_OFF,
|
||||
QB_IPCS_RATE_OFF_2,
|
||||
};
|
||||
|
||||
struct qb_ipcs_connection;
|
||||
typedef struct qb_ipcs_connection qb_ipcs_connection_t;
|
||||
|
||||
struct qb_ipcs_service;
|
||||
typedef struct qb_ipcs_service qb_ipcs_service_t;
|
||||
|
||||
struct qb_ipcs_stats {
|
||||
uint32_t active_connections;
|
||||
uint32_t closed_connections;
|
||||
};
|
||||
|
||||
struct qb_ipcs_connection_stats {
|
||||
int32_t client_pid;
|
||||
uint64_t requests;
|
||||
uint64_t responses;
|
||||
uint64_t events;
|
||||
uint64_t send_retries;
|
||||
uint64_t recv_retries;
|
||||
int32_t flow_control_state;
|
||||
uint64_t flow_control_count;
|
||||
};
|
||||
|
||||
typedef int32_t (*qb_ipcs_dispatch_fn_t) (int32_t fd, int32_t revents,
|
||||
void *data);
|
||||
|
||||
typedef int32_t (*qb_ipcs_dispatch_add_fn)(enum qb_loop_priority p,
|
||||
int32_t fd,
|
||||
int32_t events,
|
||||
void *data,
|
||||
qb_ipcs_dispatch_fn_t fn);
|
||||
typedef int32_t (*qb_ipcs_dispatch_mod_fn)(enum qb_loop_priority p,
|
||||
int32_t fd,
|
||||
int32_t events,
|
||||
void *data,
|
||||
qb_ipcs_dispatch_fn_t fn);
|
||||
typedef int32_t (*qb_ipcs_dispatch_del_fn)(int32_t fd);
|
||||
|
||||
typedef int32_t (*qb_ipcs_job_add_fn)(enum qb_loop_priority p,
|
||||
void *data,
|
||||
qb_loop_job_dispatch_fn dispatch_fn);
|
||||
|
||||
struct qb_ipcs_poll_handlers {
|
||||
qb_ipcs_job_add_fn job_add;
|
||||
qb_ipcs_dispatch_add_fn dispatch_add;
|
||||
qb_ipcs_dispatch_mod_fn dispatch_mod;
|
||||
qb_ipcs_dispatch_del_fn dispatch_del;
|
||||
};
|
||||
|
||||
/**
|
||||
* This callback is to check wether you want to accept a new connection.
|
||||
*
|
||||
* The type of checks you should do are authentication, service availabilty
|
||||
* or process resource constraints.
|
||||
* @return 0 to accept or -errno to indicate a failure (sent back to the client)
|
||||
*/
|
||||
typedef int32_t (*qb_ipcs_connection_accept_fn) (qb_ipcs_connection_t *c, uid_t uid, gid_t gid);
|
||||
|
||||
/**
|
||||
* This is called after a new connection has been created.
|
||||
*/
|
||||
typedef void (*qb_ipcs_connection_created_fn) (qb_ipcs_connection_t *c);
|
||||
|
||||
/**
|
||||
* This is called after a connection has been disconnected.
|
||||
*
|
||||
* @note if you return anything but 0 this function will be
|
||||
* repeativily called (until 0 is returned).
|
||||
*/
|
||||
typedef int32_t (*qb_ipcs_connection_closed_fn) (qb_ipcs_connection_t *c);
|
||||
|
||||
/**
|
||||
* This is called just before a connection is freed.
|
||||
*/
|
||||
typedef void (*qb_ipcs_connection_destroyed_fn) (qb_ipcs_connection_t *c);
|
||||
|
||||
/**
|
||||
* This is the message processing calback.
|
||||
* It is called with the message data.
|
||||
*/
|
||||
typedef int32_t (*qb_ipcs_msg_process_fn) (qb_ipcs_connection_t *c,
|
||||
void *data, size_t size);
|
||||
|
||||
struct qb_ipcs_service_handlers {
|
||||
qb_ipcs_connection_accept_fn connection_accept;
|
||||
qb_ipcs_connection_created_fn connection_created;
|
||||
qb_ipcs_msg_process_fn msg_process;
|
||||
qb_ipcs_connection_closed_fn connection_closed;
|
||||
qb_ipcs_connection_destroyed_fn connection_destroyed;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new IPC server.
|
||||
*
|
||||
* @param name for clients to connect to.
|
||||
* @param service_id an integer to associate with the service
|
||||
* @param type transport type.
|
||||
* @param handlers callbacks.
|
||||
* @return the new service instance.
|
||||
*/
|
||||
qb_ipcs_service_t* qb_ipcs_create(const char *name,
|
||||
int32_t service_id,
|
||||
enum qb_ipc_type type,
|
||||
struct qb_ipcs_service_handlers *handlers);
|
||||
|
||||
|
||||
/**
|
||||
* Increase the reference counter on the service object.
|
||||
*
|
||||
* @param s service instance
|
||||
*/
|
||||
void qb_ipcs_ref(qb_ipcs_service_t *s);
|
||||
|
||||
/**
|
||||
* Decrease the reference counter on the service object.
|
||||
*
|
||||
* @param s service instance
|
||||
*/
|
||||
void qb_ipcs_unref(qb_ipcs_service_t *s);
|
||||
|
||||
/**
|
||||
* Set your poll callbacks.
|
||||
*
|
||||
* @param s service instance
|
||||
* @param handlers the handlers that you want ipcs to use.
|
||||
*/
|
||||
void qb_ipcs_poll_handlers_set(qb_ipcs_service_t* s,
|
||||
struct qb_ipcs_poll_handlers *handlers);
|
||||
|
||||
/**
|
||||
* run the new IPC server.
|
||||
* @param s service instance
|
||||
* @return 0 == ok; -errno to indicate a failure
|
||||
*/
|
||||
int32_t qb_ipcs_run(qb_ipcs_service_t* s);
|
||||
|
||||
/**
|
||||
* Destroy the IPC server.
|
||||
*
|
||||
* @param s service instance to destroy
|
||||
*/
|
||||
void qb_ipcs_destroy(qb_ipcs_service_t* s);
|
||||
|
||||
/**
|
||||
* Limit the incomming request rate.
|
||||
* @param s service instance
|
||||
* @param rl the new rate
|
||||
*/
|
||||
void qb_ipcs_request_rate_limit(qb_ipcs_service_t* s, enum qb_ipcs_rate_limit rl);
|
||||
|
||||
/**
|
||||
* Send a response to a incomming request.
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param data the message to send
|
||||
* @param size the size of the message
|
||||
* @return size sent or -errno for errors
|
||||
*/
|
||||
ssize_t qb_ipcs_response_send(qb_ipcs_connection_t *c, const void *data, size_t size);
|
||||
|
||||
/**
|
||||
* Send a response to a incomming request.
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param iov the iovec struct that points to the message to send
|
||||
* @param iov_len the number of iovecs.
|
||||
* @return size sent or -errno for errors
|
||||
*/
|
||||
ssize_t qb_ipcs_response_sendv(qb_ipcs_connection_t *c, const struct iovec * iov, size_t iov_len);
|
||||
|
||||
/**
|
||||
* Send an asyncronous event message to the client.
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param data the message to send
|
||||
* @param size the size of the message
|
||||
* @return size sent or -errno for errors
|
||||
*/
|
||||
ssize_t qb_ipcs_event_send(qb_ipcs_connection_t *c, const void *data, size_t size);
|
||||
|
||||
/**
|
||||
* Send an asyncronous event message to the client.
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param iov the iovec struct that points to the message to send
|
||||
* @param iov_len the number of iovecs.
|
||||
* @return size sent or -errno for errors
|
||||
*/
|
||||
ssize_t qb_ipcs_event_sendv(qb_ipcs_connection_t *c, const struct iovec * iov, size_t iov_len);
|
||||
|
||||
/**
|
||||
* Increment the connection's reference counter.
|
||||
*
|
||||
* @param c connection instance
|
||||
*/
|
||||
void qb_ipcs_connection_ref(qb_ipcs_connection_t *c);
|
||||
|
||||
/**
|
||||
* Decrement the connection's reference counter.
|
||||
*
|
||||
* @param c connection instance
|
||||
*/
|
||||
void qb_ipcs_connection_unref(qb_ipcs_connection_t *c);
|
||||
|
||||
/**
|
||||
* Disconnect from this client.
|
||||
*
|
||||
* @param c connection instance
|
||||
*/
|
||||
void qb_ipcs_disconnect(qb_ipcs_connection_t *c);
|
||||
|
||||
/**
|
||||
* Get the service id related to this connection's service.
|
||||
* (as passed into qb_ipcs_create()
|
||||
*
|
||||
* @return service id.
|
||||
*/
|
||||
int32_t qb_ipcs_service_id_get(qb_ipcs_connection_t *c);
|
||||
|
||||
/**
|
||||
* Associate a "user" pointer with this connection.
|
||||
*
|
||||
* @param context the point to associate with this connection.
|
||||
* @param c connection instance
|
||||
* @see qb_ipcs_context_get()
|
||||
*/
|
||||
void qb_ipcs_context_set(qb_ipcs_connection_t *c, void *context);
|
||||
|
||||
/**
|
||||
* Get the context (set previously)
|
||||
*
|
||||
* @param c connection instance
|
||||
* @return the context
|
||||
* @see qb_ipcs_context_set()
|
||||
*/
|
||||
void *qb_ipcs_context_get(qb_ipcs_connection_t *c);
|
||||
|
||||
/**
|
||||
* Get the connection statistics.
|
||||
*
|
||||
* @param stats (out) the statistics structure
|
||||
* @param clear_after_read clear stats after copying them into stats
|
||||
* @param c connection instance
|
||||
* @return 0 == ok; -errno to indicate a failure
|
||||
*/
|
||||
int32_t qb_ipcs_connection_stats_get(qb_ipcs_connection_t *c,
|
||||
struct qb_ipcs_connection_stats* stats,
|
||||
int32_t clear_after_read);
|
||||
|
||||
/**
|
||||
* Get the service statistics.
|
||||
*
|
||||
* @param stats (out) the statistics structure
|
||||
* @param clear_after_read clear stats after copying them into stats
|
||||
* @param pt service instance
|
||||
* @return 0 == ok; -errno to indicate a failure
|
||||
*/
|
||||
int32_t qb_ipcs_stats_get(qb_ipcs_service_t* pt,
|
||||
struct qb_ipcs_stats* stats,
|
||||
int32_t clear_after_read);
|
||||
|
||||
/**
|
||||
* Get the first connection.
|
||||
*
|
||||
* @note call qb_ipcs_connection_ref_dec() after using the connection.
|
||||
*
|
||||
* @param pt service instance
|
||||
* @return first connection
|
||||
*/
|
||||
qb_ipcs_connection_t * qb_ipcs_connection_first_get(qb_ipcs_service_t* pt);
|
||||
|
||||
/**
|
||||
* Get the next connection.
|
||||
*
|
||||
* @note call qb_ipcs_connection_ref_dec() after using the connection.
|
||||
*
|
||||
* @param pt service instance
|
||||
* @param current current connection
|
||||
* @return next connection
|
||||
*/
|
||||
qb_ipcs_connection_t * qb_ipcs_connection_next_get(qb_ipcs_service_t* pt,
|
||||
qb_ipcs_connection_t *current);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* QB_IPCS_H_DEFINED */
|
||||
247
include/qb/qblist.h
Normal file
247
include/qb/qblist.h
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2010, 2009 Red Hat, Inc.
|
||||
*
|
||||
* Author: Steven Dake <sdake@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QB_LIST_H_DEFINED
|
||||
#define QB_LIST_H_DEFINED
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <qb/qbdefs.h>
|
||||
|
||||
/**
|
||||
* @file qblist.h
|
||||
* This is a kernel style list implementation.
|
||||
*
|
||||
* @author Steven Dake <sdake@redhat.com>
|
||||
*/
|
||||
|
||||
struct qb_list_head {
|
||||
struct qb_list_head *next;
|
||||
struct qb_list_head *prev;
|
||||
};
|
||||
|
||||
/**
|
||||
* @def QB_LIST_DECLARE()
|
||||
* Declare and initialize a list head.
|
||||
*/
|
||||
#define QB_LIST_DECLARE(name) \
|
||||
struct qb_list_head name = { &(name), &(name) }
|
||||
|
||||
#define QB_INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Initialize the list entry.
|
||||
*
|
||||
* Points next and prev pointers to head.
|
||||
* @param head pointer to the list head
|
||||
*/
|
||||
static inline void qb_list_init(struct qb_list_head *head)
|
||||
{
|
||||
head->next = head;
|
||||
head->prev = head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add this element to the list.
|
||||
*
|
||||
* @param element the new element to insert.
|
||||
* @param head pointer to the list head
|
||||
*/
|
||||
static inline void qb_list_add(struct qb_list_head *element,
|
||||
struct qb_list_head *head)
|
||||
{
|
||||
head->next->prev = element;
|
||||
element->next = head->next;
|
||||
element->prev = head;
|
||||
head->next = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the list (but at the end of the list).
|
||||
*
|
||||
* @param element pointer to the element to add
|
||||
* @param head pointer to the list head
|
||||
* @see qb_list_add()
|
||||
*/
|
||||
static inline void qb_list_add_tail(struct qb_list_head *element,
|
||||
struct qb_list_head *head)
|
||||
{
|
||||
head->prev->next = element;
|
||||
element->next = head;
|
||||
element->prev = head->prev;
|
||||
head->prev = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an entry from the list.
|
||||
*
|
||||
* @param _remove the list item to remove
|
||||
*/
|
||||
static inline void qb_list_del(struct qb_list_head *_remove)
|
||||
{
|
||||
_remove->next->prev = _remove->prev;
|
||||
_remove->prev->next = _remove->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* A quick test to see if the list is empty (pointing to it's self).
|
||||
* @param head pointer to the list head
|
||||
* @return boolean true/false
|
||||
*/
|
||||
static inline int32_t qb_list_empty(const struct qb_list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join two lists.
|
||||
* @param list the new list to add.
|
||||
* @param head the place to add it in the first list.
|
||||
*
|
||||
* @note The "list" is reinitialised
|
||||
*/
|
||||
static inline void qb_list_splice(struct qb_list_head *list,
|
||||
struct qb_list_head *head)
|
||||
{
|
||||
struct qb_list_head *first = list->next;
|
||||
struct qb_list_head *last = list->prev;
|
||||
struct qb_list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the struct for this entry
|
||||
* @param ptr: the &struct list_head pointer.
|
||||
* @param type: the type of the struct this is embedded in.
|
||||
* @param member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define qb_list_entry(ptr,type,member)\
|
||||
((type *)((char *)(ptr)-(char*)(&((type *)0)->member)))
|
||||
|
||||
|
||||
/**
|
||||
* Iterate over a list
|
||||
* @param pos: the &struct list_head to use as a loop counter.
|
||||
* @param head: the head for your list.
|
||||
*/
|
||||
#define qb_list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* Iterate over a list backwards
|
||||
* @param pos: the &struct list_head to use as a loop counter.
|
||||
* @param head: the head for your list.
|
||||
*/
|
||||
#define qb_list_for_each_reverse(pos, head) \
|
||||
for (pos = (head)->prev; pos != (head); pos = pos->prev)
|
||||
|
||||
/**
|
||||
* Iterate over a list safe against removal of list entry
|
||||
* @param pos: the &struct list_head to use as a loop counter.
|
||||
* @param n: another &struct list_head to use as temporary storage
|
||||
* @param head: the head for your list.
|
||||
*/
|
||||
#define qb_list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/**
|
||||
* Iterate over list of given type
|
||||
* @param pos: the type * to use as a loop counter.
|
||||
* @param head: the head for your list.
|
||||
* @param member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define qb_list_for_each_entry(pos, head, member) \
|
||||
for (pos = qb_list_entry((head)->next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = qb_list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* Iterate backwards over list of given type.
|
||||
* @param pos: the type to use as a loop counter.
|
||||
* @param head: the head for your list.
|
||||
* @param member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define qb_list_for_each_entry_reverse(pos, head, member) \
|
||||
for (pos = qb_list_entry((head)->prev, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = qb_list_entry(pos->member.prev, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* Iterate over list of given type safe against removal of list entry
|
||||
* @param pos: the type * to use as a loop cursor.
|
||||
* @param n: another type * to use as temporary storage
|
||||
* @param head: the head for your list.
|
||||
* @param member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define qb_list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = qb_list_entry((head)->next, typeof(*pos), member), \
|
||||
n = qb_list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = qb_list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* Iterate backwards over list safe against removal
|
||||
* @param pos: the type * to use as a loop cursor.
|
||||
* @param n: another type * to use as temporary storage
|
||||
* @param head: the head for your list.
|
||||
* @param member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define qb_list_for_each_entry_safe_reverse(pos, n, head, member) \
|
||||
for (pos = qb_list_entry((head)->prev, typeof(*pos), member), \
|
||||
n = qb_list_entry(pos->member.prev, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = qb_list_entry(n->member.prev, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* Count the number of items in the list.
|
||||
* @param head: the head for your list.
|
||||
* @return length of the list.
|
||||
*/
|
||||
static inline int32_t qb_list_length(struct qb_list_head *head)
|
||||
{
|
||||
struct qb_list_head *item;
|
||||
int32_t length = 0;
|
||||
|
||||
qb_list_for_each(item, head)
|
||||
length++;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* QB_LIST_H_DEFINED */
|
||||
627
include/qb/qblog.h
Normal file
627
include/qb/qblog.h
Normal file
@ -0,0 +1,627 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QB_LOG_H_DEFINED
|
||||
#define QB_LOG_H_DEFINED
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <qb/qbutil.h>
|
||||
#include <qb/qbconfig.h>
|
||||
|
||||
#ifdef S_SPLINT_S
|
||||
#undef QB_HAVE_ATTRIBUTE_SECTION
|
||||
#endif /* S_SPLINT_S */
|
||||
|
||||
/**
|
||||
* @file qblog.h
|
||||
* The logging API provides four main parts (basics, filtering, threading & blackbox).
|
||||
*
|
||||
* The idea behind this logging system is not to be prescriptive but to provide a
|
||||
* set of tools to help the developer achieve what they want quickly and easily.
|
||||
*
|
||||
* @par Basic logging API.
|
||||
* Call qb_log() to generate a log message. Then to write the message
|
||||
* somewhere meaningful call qb_log_ctl() to configure the targets.
|
||||
*
|
||||
* Simplist possible use:
|
||||
* @code
|
||||
* main() {
|
||||
* qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
|
||||
* // ...
|
||||
* qb_log(LOG_WARNING, "watch out");
|
||||
* // ...
|
||||
* qb_log_fini();
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @par Configuring log targets.
|
||||
* A log target can by syslog, stderr, the blackbox or a text file.
|
||||
* By default only syslog is enabled.
|
||||
*
|
||||
* To enable a target do the following
|
||||
* @code
|
||||
* qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
* @endcode
|
||||
*
|
||||
* syslog, stderr and the blackbox are static (they don't need
|
||||
* to be created, just enabled or disabled. However you can open multiple
|
||||
* logfiles (32 - QB_LOG_BLACKBOX). To do this use the following code.
|
||||
* @code
|
||||
* mytarget = qb_log_file_open("/var/log/mylogfile");
|
||||
* qb_log_ctl(mytarget, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
* @endcode
|
||||
*
|
||||
* Once your targets are enabled/opened you can configure them as follows:
|
||||
* Configure the size of blackbox
|
||||
* @code
|
||||
* qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024*10);
|
||||
* @endcode
|
||||
*
|
||||
* Make logging to file threaded:
|
||||
* @code
|
||||
* qb_log_ctl(mytarget, QB_LOG_CONF_THREADED, QB_TRUE);
|
||||
* @endcode
|
||||
*
|
||||
* To workaround your syslog daemon filtering all messages > LOG_INFO
|
||||
* @code
|
||||
* qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_PRIORITY_BUMP,
|
||||
* LOG_INFO - LOG_DEBUG);
|
||||
* @endcode
|
||||
*
|
||||
* @par Filtering messages.
|
||||
* To have more power over what log messages go to which target you can apply
|
||||
* filters to the targets. What happens is the desired callsites have the
|
||||
* correct bit set. Then when the log message is generated it gets sent to the
|
||||
* targets based on which bit is set in the callsite's "target" bitmap.
|
||||
* Messages can be filtered based on the:
|
||||
* -# filename + priority
|
||||
* -# function name + priority
|
||||
* -# format string + priority
|
||||
*
|
||||
* So to make all logs from evil_fnunction() go to stderr do the following:
|
||||
* @code
|
||||
* qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
|
||||
* QB_LOG_FILTER_FUNCTION, "evil_fnunction", LOG_TRACE);
|
||||
* @endcode
|
||||
*
|
||||
* So to make all logs from totem* (with a priority <= LOG_INFO) go to stderr do the following:
|
||||
* @code
|
||||
* qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
|
||||
* QB_LOG_FILTER_FILE, "totem", LOG_INFO);
|
||||
* @endcode
|
||||
*
|
||||
* So to make all logs with the substring "ringbuffer" go to stderr do the following:
|
||||
* @code
|
||||
* qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
|
||||
* QB_LOG_FILTER_FORMAT, "ringbuffer", LOG_TRACE);
|
||||
* @endcode
|
||||
*
|
||||
* @par Threaded logging.
|
||||
* To achieve non-blocking logging you can use threaded logging. So any
|
||||
* calls to write() or syslog() will not hold up your program.
|
||||
*
|
||||
* Threaded logging use:
|
||||
* @code
|
||||
* main() {
|
||||
* qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
|
||||
* qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_THREADED, QB_TRUE);
|
||||
* // ...
|
||||
* daemonize();
|
||||
* // call this after you fork()
|
||||
* qb_log_thread_start();
|
||||
* // ...
|
||||
* qb_log(LOG_WARNING, "watch out");
|
||||
* // ...
|
||||
* qb_log_fini();
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @par A blackbox for in-field diagnosis.
|
||||
* This stores log messages in a ringbuffer so they can be written to
|
||||
* file if the program crashes (you will need to catch SIGSEGV). These
|
||||
* can then be easily printed out later.
|
||||
*
|
||||
* @note the blackbox is not enabled by default.
|
||||
*
|
||||
* Blackbox usage:
|
||||
* @code
|
||||
*
|
||||
* static void sigsegv_handler(int sig)
|
||||
* {
|
||||
* (void)signal (SIGSEGV, SIG_DFL);
|
||||
* qb_log_blackbox_write_to_file("simple-log.fdata");
|
||||
* qb_log_fini();
|
||||
* raise(SIGSEGV);
|
||||
* }
|
||||
*
|
||||
* main() {
|
||||
*
|
||||
* signal(SIGSEGV, sigsegv_handler);
|
||||
*
|
||||
* qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
|
||||
* qb_log_filter_ctl(QB_LOG_BLACKBOX, QB_LOG_FILTER_ADD,
|
||||
* QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
|
||||
* qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024*10);
|
||||
* qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
* // ...
|
||||
* qb_log(LOG_WARNING, "watch out");
|
||||
* // ...
|
||||
* qb_log_fini();
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @par Tagging messages.
|
||||
* You can tag messages using the second argument to qb_logt() or
|
||||
* by using qb_log_filter_ctl().
|
||||
* This can be used to add feature or sub-system information to the logs.
|
||||
*
|
||||
* @code
|
||||
* const char* my_tags_stringify(uint32_t tags) {
|
||||
* if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT) {
|
||||
* return "libqb";
|
||||
* } else if (tags == 3) {
|
||||
* return "three";
|
||||
* } else {
|
||||
* return "MAIN";
|
||||
* }
|
||||
* }
|
||||
* main() {
|
||||
* // ...
|
||||
* qb_log_tags_stringify_fn_set(my_tags_stringify);
|
||||
* qb_log_format_set(QB_LOG_STDERR, "[%5g] %p %b");
|
||||
* // ...
|
||||
* qb_logt(LOG_INFO, 3, "hello");
|
||||
* qb_logt(LOG_INFO, 0, "hello");
|
||||
* }
|
||||
* @endcode
|
||||
* The code above will produce:
|
||||
* @code
|
||||
* [libqb] some message
|
||||
* [three] info hello
|
||||
* [MAIN ] info hello
|
||||
* @endcode
|
||||
*
|
||||
* @example simplelog.c
|
||||
*/
|
||||
|
||||
#undef LOG_TRACE
|
||||
#define LOG_TRACE (LOG_DEBUG + 1)
|
||||
|
||||
#define QB_LOG_MAX_LEN 512
|
||||
#define QB_LOG_STRERROR_MAX_LEN 128
|
||||
|
||||
typedef const char *(*qb_log_tags_stringify_fn)(uint32_t tags);
|
||||
|
||||
/**
|
||||
* An instance of this structure is created in a special
|
||||
* ELF section at every dynamic debug callsite. At runtime,
|
||||
* the special section is treated as an array of these.
|
||||
*/
|
||||
struct qb_log_callsite {
|
||||
const char *function;
|
||||
const char *filename;
|
||||
const char *format;
|
||||
uint8_t priority;
|
||||
uint32_t lineno;
|
||||
uint32_t targets;
|
||||
uint32_t tags;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
typedef void (*qb_log_filter_fn)(struct qb_log_callsite * cs);
|
||||
|
||||
/* will be assigned by ld linker magic */
|
||||
#ifdef QB_HAVE_ATTRIBUTE_SECTION
|
||||
extern struct qb_log_callsite __start___verbose[];
|
||||
extern struct qb_log_callsite __stop___verbose[];
|
||||
|
||||
#define QB_LOG_INIT_DATA(name) \
|
||||
void name(void); \
|
||||
void name(void) { if (__start___verbose != __stop___verbose) {assert(1);} } \
|
||||
void __attribute__ ((constructor)) name(void);
|
||||
#else
|
||||
#define QB_LOG_INIT_DATA(name)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Internal function: use qb_log() or qb_logt()
|
||||
*/
|
||||
void qb_log_real_(struct qb_log_callsite *cs, ...);
|
||||
void qb_log_real_va_(struct qb_log_callsite *cs, va_list ap);
|
||||
|
||||
#define QB_LOG_TAG_LIBQB_MSG_BIT 31
|
||||
#define QB_LOG_TAG_LIBQB_MSG (1 << QB_LOG_TAG_LIBQB_MSG_BIT)
|
||||
|
||||
/**
|
||||
* This function is to import logs from other code (like libraries)
|
||||
* that provide a callback with their logs.
|
||||
*
|
||||
* @note the performance of this will not impress you, as
|
||||
* the filtering is done on each log message, not
|
||||
* before hand. So try doing basic pre-filtering.
|
||||
*
|
||||
* @param function originating function name
|
||||
* @param filename originating filename
|
||||
* @param format format string
|
||||
* @param priority this takes syslog priorities.
|
||||
* @param lineno file line number
|
||||
* @param tags this is a uint32_t that you can use with
|
||||
* qb_log_tags_stringify_fn_set() to "tag" a log message
|
||||
* with a feature or sub-system then you can use "%g"
|
||||
* in the format specifer to print it out.
|
||||
*/
|
||||
void qb_log_from_external_source(const char *function,
|
||||
const char *filename,
|
||||
const char *format,
|
||||
uint8_t priority,
|
||||
uint32_t lineno,
|
||||
uint32_t tags,
|
||||
...);
|
||||
|
||||
/**
|
||||
* Get or create a callsite at the give position.
|
||||
*
|
||||
* The result can then be passed into qb_log_real_()
|
||||
*
|
||||
* @param function originating function name
|
||||
* @param filename originating filename
|
||||
* @param format format string
|
||||
* @param priority this takes syslog priorities.
|
||||
* @param lineno file line number
|
||||
* @param tags the tag
|
||||
*/
|
||||
struct qb_log_callsite* qb_log_callsite_get(const char *function,
|
||||
const char *filename,
|
||||
const char *format,
|
||||
uint8_t priority,
|
||||
uint32_t lineno,
|
||||
uint32_t tags);
|
||||
|
||||
void qb_log_from_external_source_va(const char *function,
|
||||
const char *filename,
|
||||
const char *format,
|
||||
uint8_t priority,
|
||||
uint32_t lineno,
|
||||
uint32_t tags,
|
||||
va_list ap);
|
||||
|
||||
/**
|
||||
* This is the function to generate a log message if you want to
|
||||
* manually add tags.
|
||||
*
|
||||
* @param priority this takes syslog priorities.
|
||||
* @param tags this is a uint32_t that you can use with
|
||||
* qb_log_tags_stringify_fn_set() to "tag" a log message
|
||||
* with a feature or sub-system then you can use "%g"
|
||||
* in the format specifer to print it out.
|
||||
* @param fmt usual printf style format specifiers
|
||||
* @param args usual printf style args
|
||||
*/
|
||||
#ifdef QB_HAVE_ATTRIBUTE_SECTION
|
||||
#define qb_logt(priority, tags, fmt, args...) do { \
|
||||
static struct qb_log_callsite descriptor \
|
||||
__attribute__((section("__verbose"), aligned(8))) = \
|
||||
{ __func__, __FILE__, fmt, priority, __LINE__, 0, tags }; \
|
||||
qb_log_real_(&descriptor, ##args); \
|
||||
} while(0)
|
||||
#else
|
||||
#define qb_logt(priority, tags, fmt, args...) do { \
|
||||
struct qb_log_callsite* descriptor_pt = \
|
||||
qb_log_callsite_get(__func__, __FILE__, fmt, \
|
||||
priority, __LINE__, tags); \
|
||||
qb_log_real_(descriptor_pt, ##args); \
|
||||
} while(0)
|
||||
#endif /* QB_HAVE_ATTRIBUTE_SECTION */
|
||||
|
||||
|
||||
/**
|
||||
* This is the main function to generate a log message.
|
||||
*
|
||||
* @param priority this takes syslog priorities.
|
||||
* @param fmt usual printf style format specifiers
|
||||
* @param args usual printf style args
|
||||
*/
|
||||
#define qb_log(priority, fmt, args...) qb_logt(priority, 0, fmt, ##args)
|
||||
|
||||
/**
|
||||
* This is similar to perror except it goes into the logging system.
|
||||
*
|
||||
* @param priority this takes syslog priorities.
|
||||
* @param fmt usual printf style format specifiers
|
||||
* @param args usual printf style args
|
||||
*/
|
||||
#ifndef S_SPLINT_S
|
||||
#define qb_perror(priority, fmt, args...) do { \
|
||||
char _perr_buf_[QB_LOG_STRERROR_MAX_LEN]; \
|
||||
const char *_perr_str_ = qb_strerror_r(errno, _perr_buf_, sizeof(_perr_buf_)); \
|
||||
qb_logt(priority, 0, fmt ": %s (%d)", ##args, _perr_str_, errno); \
|
||||
} while(0)
|
||||
#else
|
||||
#define qb_perror
|
||||
#endif
|
||||
|
||||
#define qb_enter() qb_log(LOG_TRACE, "ENTERING %s()", __func__)
|
||||
#define qb_leave() qb_log(LOG_TRACE, "LEAVING %s()", __func__)
|
||||
|
||||
#define QB_LOG_SYSLOG 0
|
||||
#define QB_LOG_STDERR 1
|
||||
#define QB_LOG_BLACKBOX 2
|
||||
#define QB_LOG_STDOUT 3
|
||||
|
||||
#define QB_LOG_TARGET_MAX 32
|
||||
|
||||
enum qb_log_target_state {
|
||||
QB_LOG_STATE_UNUSED = 1,
|
||||
QB_LOG_STATE_DISABLED = 2,
|
||||
QB_LOG_STATE_ENABLED = 3,
|
||||
};
|
||||
|
||||
enum qb_log_conf {
|
||||
QB_LOG_CONF_ENABLED,
|
||||
QB_LOG_CONF_FACILITY,
|
||||
QB_LOG_CONF_DEBUG,
|
||||
QB_LOG_CONF_SIZE,
|
||||
QB_LOG_CONF_THREADED,
|
||||
QB_LOG_CONF_PRIORITY_BUMP,
|
||||
QB_LOG_CONF_STATE_GET,
|
||||
};
|
||||
|
||||
enum qb_log_filter_type {
|
||||
QB_LOG_FILTER_FILE,
|
||||
QB_LOG_FILTER_FUNCTION,
|
||||
QB_LOG_FILTER_FORMAT,
|
||||
};
|
||||
|
||||
enum qb_log_filter_conf {
|
||||
QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_REMOVE,
|
||||
QB_LOG_FILTER_CLEAR_ALL,
|
||||
QB_LOG_TAG_SET,
|
||||
QB_LOG_TAG_CLEAR,
|
||||
QB_LOG_TAG_CLEAR_ALL,
|
||||
};
|
||||
|
||||
typedef void (*qb_log_logger_fn)(int32_t t,
|
||||
struct qb_log_callsite *cs,
|
||||
time_t timestamp,
|
||||
const char *msg);
|
||||
typedef void (*qb_log_vlogger_fn)(int32_t t,
|
||||
struct qb_log_callsite *cs,
|
||||
time_t timestamp,
|
||||
va_list ap);
|
||||
|
||||
typedef void (*qb_log_close_fn)(int32_t t);
|
||||
typedef void (*qb_log_reload_fn)(int32_t t);
|
||||
|
||||
/**
|
||||
* Init the logging system.
|
||||
*
|
||||
* @param name will be passed into openlog()
|
||||
* @param facility default for all new targets.
|
||||
* @param priority a basic filter with this priority will be added.
|
||||
*/
|
||||
void qb_log_init(const char *name,
|
||||
int32_t facility,
|
||||
uint8_t priority);
|
||||
|
||||
/**
|
||||
* Logging system finalization function.
|
||||
*
|
||||
* It releases any shared memory.
|
||||
* Stops the logging thread if running.
|
||||
* Flushes the last message to their destinations.
|
||||
*/
|
||||
void qb_log_fini(void);
|
||||
|
||||
/**
|
||||
* If you are using dynamically loadable modules via dlopen() and
|
||||
* you load them after qb_log_init() then after you load the module
|
||||
* you will need to do the following to get the filters to work
|
||||
* in that module.
|
||||
* @code
|
||||
* _start = dlsym (dl_handle, "__start___verbose");
|
||||
* _stop = dlsym (dl_handle, "__stop___verbose");
|
||||
* qb_log_callsites_register(_start, _stop);
|
||||
* @endcode
|
||||
*/
|
||||
int32_t qb_log_callsites_register(struct qb_log_callsite *_start, struct qb_log_callsite *_stop);
|
||||
|
||||
/**
|
||||
* Dump the callsite info to stdout.
|
||||
*/
|
||||
void qb_log_callsites_dump(void);
|
||||
|
||||
/**
|
||||
* Main logging control function.
|
||||
*
|
||||
* @param target QB_LOG_SYSLOG, QB_LOG_STDERR or result from qb_log_file_open()
|
||||
* @param conf_type what to configure
|
||||
* @param arg the new value
|
||||
* @see qb_log_conf
|
||||
*
|
||||
* @retval -errno on error
|
||||
* @retval 0 on success
|
||||
* @retval qb_log_target_state for QB_LOG_CONF_STATE_GET
|
||||
*/
|
||||
int32_t qb_log_ctl(int32_t target, enum qb_log_conf conf_type, int32_t arg);
|
||||
|
||||
/**
|
||||
* This allows you modify the 'tags' and 'targets' callsite fields at runtime.
|
||||
*/
|
||||
int32_t qb_log_filter_ctl(int32_t value, enum qb_log_filter_conf c,
|
||||
enum qb_log_filter_type type, const char * text,
|
||||
uint8_t low_priority);
|
||||
|
||||
|
||||
/**
|
||||
* This extends qb_log_filter_ctl() by been able to provide a high_priority.
|
||||
*/
|
||||
int32_t qb_log_filter_ctl2(int32_t value, enum qb_log_filter_conf c,
|
||||
enum qb_log_filter_type type, const char * text,
|
||||
uint8_t high_priority, uint8_t low_priority);
|
||||
|
||||
|
||||
/**
|
||||
* Instead of using the qb_log_filter_ctl() functions you
|
||||
* can apply the filters manually by defining a callback
|
||||
* and setting the targets field using qb_bit_set() and
|
||||
* qb_bit_clear() like the following below.
|
||||
* @code
|
||||
* static void
|
||||
* m_filter(struct qb_log_callsite *cs)
|
||||
* {
|
||||
* if ((cs->priority >= LOG_ALERT &&
|
||||
* cs->priority <= LOG_DEBUG) &&
|
||||
* strcmp(cs->filename, "my_c_file.c") == 0) {
|
||||
* qb_bit_set(cs->targets, QB_LOG_SYSLOG);
|
||||
* } else {
|
||||
* qb_bit_clear(cs->targets, QB_LOG_SYSLOG);
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
int32_t qb_log_filter_fn_set(qb_log_filter_fn fn);
|
||||
|
||||
/**
|
||||
* Set the callback to map the 'tags' bit map to a string.
|
||||
*/
|
||||
void qb_log_tags_stringify_fn_set(qb_log_tags_stringify_fn fn);
|
||||
|
||||
/**
|
||||
* Set the format specifiers.
|
||||
*
|
||||
* %n FUNCTION NAME
|
||||
* %f FILENAME
|
||||
* %l FILELINE
|
||||
* %p PRIORITY
|
||||
* %t TIMESTAMP
|
||||
* %b BUFFER
|
||||
* %g TAGS
|
||||
* %N name (passed into qb_log_init)
|
||||
* %P PID
|
||||
* %H hostname
|
||||
*
|
||||
* any number between % and character specify field length to pad or chop
|
||||
*/
|
||||
void qb_log_format_set(int32_t t, const char* format);
|
||||
|
||||
/**
|
||||
* Open a log file.
|
||||
*
|
||||
* @retval -errno on error
|
||||
* @retval 3 to 31 (to be passed into other qb_log_* functions)
|
||||
*/
|
||||
int32_t qb_log_file_open(const char *filename);
|
||||
|
||||
/**
|
||||
* Close a log file and release is resources.
|
||||
*/
|
||||
void qb_log_file_close(int32_t t);
|
||||
|
||||
/**
|
||||
* When using threaded logging set the pthread policy and priority.
|
||||
*
|
||||
* @retval -errno on error
|
||||
* @retval 0 success
|
||||
*/
|
||||
int32_t qb_log_thread_priority_set(int32_t policy, int32_t priority);
|
||||
|
||||
/**
|
||||
* Start the logging pthread.
|
||||
*/
|
||||
int32_t qb_log_thread_start(void);
|
||||
|
||||
/**
|
||||
* Write the blackbox to file.
|
||||
*/
|
||||
ssize_t qb_log_blackbox_write_to_file(const char *filename);
|
||||
|
||||
/**
|
||||
* Read the blackbox for file and print it out.
|
||||
*/
|
||||
void qb_log_blackbox_print_from_file(const char* filename);
|
||||
|
||||
/**
|
||||
* Open a custom log target.
|
||||
*
|
||||
* @retval -errno on error
|
||||
* @retval 3 to 31 (to be passed into other qb_log_* functions)
|
||||
*/
|
||||
int32_t qb_log_custom_open(qb_log_logger_fn log_fn,
|
||||
qb_log_close_fn close_fn,
|
||||
qb_log_reload_fn reload_fn,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Close a custom log target and release is resources.
|
||||
*/
|
||||
void qb_log_custom_close(int32_t t);
|
||||
|
||||
/**
|
||||
* Retrieve the user data set by either qb_log_custom_open or
|
||||
* qb_log_target_user_data_set.
|
||||
*/
|
||||
void *qb_log_target_user_data_get(int32_t t);
|
||||
|
||||
/**
|
||||
* Associate user data with this log target
|
||||
* @note only use this with custom targets
|
||||
*/
|
||||
int32_t qb_log_target_user_data_set(int32_t t, void *user_data);
|
||||
|
||||
/**
|
||||
* format the callsite and timestamp info according to the format
|
||||
* set using qb_log_format_set()
|
||||
* It is intended to be used from your custom logger function.
|
||||
*/
|
||||
void qb_log_target_format(int32_t target,
|
||||
struct qb_log_callsite *cs,
|
||||
time_t timestamp,
|
||||
const char* formatted_message,
|
||||
char *output_buffer);
|
||||
|
||||
/**
|
||||
* Convert string "auth" to equivalent number "LOG_AUTH" etc.
|
||||
*/
|
||||
int32_t qb_log_facility2int(const char *fname);
|
||||
|
||||
/**
|
||||
* Convert number "LOG_AUTH" to equivalent string "auth" etc.
|
||||
*/
|
||||
const char * qb_log_facility2str(int32_t fnum);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
/* *INDENT-ON* */
|
||||
#endif /* QB_LOG_H_DEFINED */
|
||||
289
include/qb/qbloop.h
Normal file
289
include/qb/qbloop.h
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QB_LOOP_H_DEFINED
|
||||
#define QB_LOOP_H_DEFINED
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @file qbloop.h
|
||||
*
|
||||
* Main loop manages timers, jobs and polling sockets.
|
||||
*
|
||||
* @example tcpserver.c
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Priorites for jobs, timers & poll
|
||||
*/
|
||||
enum qb_loop_priority {
|
||||
QB_LOOP_LOW = 0,
|
||||
QB_LOOP_MED = 1,
|
||||
QB_LOOP_HIGH = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* An opaque data type representing the main loop.
|
||||
*/
|
||||
typedef struct qb_loop qb_loop_t;
|
||||
|
||||
typedef uint64_t qb_loop_timer_handle;
|
||||
|
||||
typedef void *qb_loop_signal_handle;
|
||||
|
||||
typedef int32_t (*qb_loop_poll_dispatch_fn) (int32_t fd, int32_t revents, void *data);
|
||||
typedef void (*qb_loop_job_dispatch_fn)(void *data);
|
||||
typedef void (*qb_loop_timer_dispatch_fn)(void *data);
|
||||
typedef int32_t (*qb_loop_signal_dispatch_fn)(int32_t rsignal, void *data);
|
||||
|
||||
typedef void (*qb_loop_poll_low_fds_event_fn) (int32_t not_enough, int32_t fds_available);
|
||||
|
||||
/**
|
||||
* Create a new main loop.
|
||||
*
|
||||
* @return loop instance.
|
||||
*/
|
||||
qb_loop_t * qb_loop_create(void);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void qb_loop_destroy(struct qb_loop * l);
|
||||
|
||||
/**
|
||||
* Stop the main loop.
|
||||
* @param l pointer to the loop instance
|
||||
*/
|
||||
void qb_loop_stop(qb_loop_t *l);
|
||||
|
||||
/**
|
||||
* Run the main loop.
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
*/
|
||||
void qb_loop_run(qb_loop_t *l);
|
||||
|
||||
|
||||
/**
|
||||
* Add a job to the mainloop.
|
||||
*
|
||||
* This is run in the next cycle of the loop.
|
||||
* @note it is a one-shot job.
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param p the priority
|
||||
* @param data user data passed into the dispatch function
|
||||
* @param dispatch_fn callback function
|
||||
* @return status (0 == ok, -errno == failure)
|
||||
*/
|
||||
int32_t qb_loop_job_add(qb_loop_t *l,
|
||||
enum qb_loop_priority p,
|
||||
void *data,
|
||||
qb_loop_job_dispatch_fn dispatch_fn);
|
||||
|
||||
|
||||
/**
|
||||
* Delete a job from the mainloop.
|
||||
*
|
||||
* This will try to delete the job if it hasn't run yet.
|
||||
*
|
||||
* @note this will remove the first job that matches the
|
||||
* paramaters (priority, data, dispatch_fn).
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param p the priority
|
||||
* @param data user data passed into the dispatch function
|
||||
* @param dispatch_fn callback function
|
||||
* @return status (0 == ok, -errno == failure)
|
||||
*/
|
||||
int32_t qb_loop_job_del(struct qb_loop *l,
|
||||
enum qb_loop_priority p,
|
||||
void *data,
|
||||
qb_loop_job_dispatch_fn dispatch_fn);
|
||||
|
||||
/**
|
||||
* Add a timer to the mainloop.
|
||||
* @note it is a one-shot job.
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param p the priority
|
||||
* @param nsec_duration nano-secs in the future to run the dispatch.
|
||||
* @param data user data passed into the dispatch function
|
||||
* @param dispatch_fn callback function
|
||||
* @param timer_handle_out handle to delete the timer if needed.
|
||||
* @return status (0 == ok, -errno == failure)
|
||||
*/
|
||||
int32_t qb_loop_timer_add(qb_loop_t *l,
|
||||
enum qb_loop_priority p,
|
||||
uint64_t nsec_duration,
|
||||
void *data,
|
||||
qb_loop_timer_dispatch_fn dispatch_fn,
|
||||
qb_loop_timer_handle * timer_handle_out);
|
||||
|
||||
/**
|
||||
* Delete a timer that is still outstanding.
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param th handle to delete the timer if needed.
|
||||
* @return status (0 == ok, -errno == failure)
|
||||
*/
|
||||
int32_t qb_loop_timer_del(qb_loop_t *l, qb_loop_timer_handle th);
|
||||
|
||||
/**
|
||||
* Check to see if a timer that is still outstanding.
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param th handle to delete the timer if needed.
|
||||
* @retval QB_TRUE yes this timer is outstanding
|
||||
* @retval QB_FALSE this timer does not exist or has expired
|
||||
*/
|
||||
int32_t qb_loop_timer_is_running(qb_loop_t *l, qb_loop_timer_handle th);
|
||||
|
||||
/**
|
||||
* Get the time remaining before it expires.
|
||||
*
|
||||
* @note if the timer has already expired it will return 0
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param th timer handle.
|
||||
* @return nano seconds left
|
||||
*/
|
||||
uint64_t qb_loop_timer_expire_time_get(struct qb_loop *l, qb_loop_timer_handle th);
|
||||
|
||||
/**
|
||||
* Set a callback to receive events on file descriptors
|
||||
* getting low.
|
||||
* @param l pointer to the loop instance
|
||||
* @param fn callback function.
|
||||
* @return status (0 == ok, -errno == failure)
|
||||
*/
|
||||
int32_t qb_loop_poll_low_fds_event_set(qb_loop_t *l,
|
||||
qb_loop_poll_low_fds_event_fn fn);
|
||||
|
||||
/**
|
||||
* Add a poll job to the mainloop.
|
||||
* @note it is a re-occuring job.
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param p the priority
|
||||
* @param fd file descriptor.
|
||||
* @param events (POLLIN|POLLOUT) etc ....
|
||||
* @param data user data passed into the dispatch function
|
||||
* @param dispatch_fn callback function
|
||||
* @return status (0 == ok, -errno == failure)
|
||||
*/
|
||||
int32_t qb_loop_poll_add(qb_loop_t *l,
|
||||
enum qb_loop_priority p,
|
||||
int32_t fd,
|
||||
int32_t events,
|
||||
void *data,
|
||||
qb_loop_poll_dispatch_fn dispatch_fn);
|
||||
|
||||
/**
|
||||
* Modify a poll job.
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param p the priority
|
||||
* @param fd file descriptor.
|
||||
* @param events (POLLIN|POLLOUT) etc ....
|
||||
* @param data user data passed into the dispatch function
|
||||
* @param dispatch_fn callback function
|
||||
* @return status (0 == ok, -errno == failure)
|
||||
*/
|
||||
int32_t qb_loop_poll_mod(qb_loop_t *l,
|
||||
enum qb_loop_priority p,
|
||||
int32_t fd,
|
||||
int32_t events,
|
||||
void *data,
|
||||
qb_loop_poll_dispatch_fn dispatch_fn);
|
||||
|
||||
/**
|
||||
* Delete a poll job.
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param fd file descriptor.
|
||||
* @return status (0 == ok, -errno == failure)
|
||||
*/
|
||||
int32_t qb_loop_poll_del(qb_loop_t *l, int32_t fd);
|
||||
|
||||
/**
|
||||
* Add a signal job.
|
||||
*
|
||||
* Get a callback on this signal (not in the context of the signal).
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param p the priority
|
||||
* @param signal (SIGHUP or SIGINT) etc ....
|
||||
* @param data user data passed into the dispatch function
|
||||
* @param dispatch_fn callback function
|
||||
* @param handle (out) a reference to the signal job
|
||||
* @return status (0 == ok, -errno == failure)
|
||||
*/
|
||||
int32_t qb_loop_signal_add(qb_loop_t *l,
|
||||
enum qb_loop_priority p,
|
||||
int32_t signal,
|
||||
void *data,
|
||||
qb_loop_signal_dispatch_fn dispatch_fn,
|
||||
qb_loop_signal_handle *handle);
|
||||
|
||||
/**
|
||||
* Modify the signal job
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param p the priority
|
||||
* @param signal (SIGHUP or SIGINT) etc ....
|
||||
* @param data user data passed into the dispatch function
|
||||
* @param dispatch_fn callback function
|
||||
* @param handle (in) a reference to the signal job
|
||||
* @return status (0 == ok, -errno == failure)
|
||||
*/
|
||||
int32_t qb_loop_signal_mod(qb_loop_t *l,
|
||||
enum qb_loop_priority p,
|
||||
int32_t signal,
|
||||
void *data,
|
||||
qb_loop_signal_dispatch_fn dispatch_fn,
|
||||
qb_loop_signal_handle handle);
|
||||
|
||||
/**
|
||||
* Delete the signal job.
|
||||
*
|
||||
* @param l pointer to the loop instance
|
||||
* @param handle (in) a reference to the signal job
|
||||
* @return status (0 == ok, -errno == failure)
|
||||
*/
|
||||
int32_t qb_loop_signal_del(qb_loop_t *l,
|
||||
qb_loop_signal_handle handle);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
/* *INDENT-ON* */
|
||||
#endif /* QB_LOOP_H_DEFINED */
|
||||
|
||||
284
include/qb/qbmap.h
Normal file
284
include/qb/qbmap.h
Normal file
@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QB_MAP_H_DEFINED
|
||||
#define QB_MAP_H_DEFINED
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef S_SPLINT_S
|
||||
#include <unistd.h>
|
||||
#endif /* S_SPLINT_S */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/**
|
||||
* @file qbmap.h
|
||||
* This provides a map interface to a Patricia trie, hashtable or skiplist.
|
||||
*
|
||||
* @par Ordering
|
||||
* The hashtable is NOT ordered, but ptrie and skiplist are.
|
||||
*
|
||||
* @par Iterating
|
||||
* Below is a simple example of how to iterate over a map.
|
||||
* @code
|
||||
* const char *p;
|
||||
* void *data;
|
||||
* qb_map_iter_t *it = qb_map_iter_create(m);
|
||||
* for (p = qb_map_iter_next(it, &data); p; p = qb_map_iter_next(it, &data)) {
|
||||
* printf("%s > %s\n", p, (char*) data);
|
||||
* }
|
||||
* qb_map_iter_free(it);
|
||||
* @endcode
|
||||
*
|
||||
* Deletion of items within the iterator is supported. But note do not
|
||||
* free the item memory in the iterator. If you need to free the data
|
||||
* items then register for a notifier and free the memory there. This
|
||||
* is required as the items are reference counted.
|
||||
* @code
|
||||
* qb_map_notify_add(m, NULL, my_map_free_handler,
|
||||
* QB_MAP_NOTIFY_FREE, NULL);
|
||||
* @endcode
|
||||
*
|
||||
* @par Notifications
|
||||
* These allow you to get callbacks when values are inserted/removed or
|
||||
* replaced.
|
||||
* @note hashtable only supports deletion and replacement notificatins.
|
||||
* There is also a special global callback for freeing deleted and replaced
|
||||
* values (QB_MAP_NOTIFY_FREE).
|
||||
* @see qb_map_notify_add() qb_map_notify_del_2()
|
||||
*
|
||||
* @par Prefix matching
|
||||
* The ptrie supports prefixes in the iterator:
|
||||
*
|
||||
* @code
|
||||
* it = qb_map_pref_iter_create(m, "aa");
|
||||
* while ((p = qb_map_iter_next(it, &data)) != NULL) {
|
||||
* printf("%s > %s\n", p, (char*)data);
|
||||
* }
|
||||
* qb_map_iter_free(it);
|
||||
* @endcode
|
||||
*
|
||||
* The ptrie also supports prefixes in notifications:
|
||||
* (remember to pass QB_MAP_NOTIFY_RECURSIVE into the notify_add.
|
||||
* @code
|
||||
* qb_map_notify_add(m, "root", my_map_notification,
|
||||
* (QB_MAP_NOTIFY_INSERTED|
|
||||
* QB_MAP_NOTIFY_DELETED|
|
||||
* QB_MAP_NOTIFY_REPLACED|
|
||||
* QB_MAP_NOTIFY_RECURSIVE),
|
||||
* NULL);
|
||||
*
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is an opaque data type representing an instance of a map.
|
||||
*/
|
||||
typedef struct qb_map qb_map_t;
|
||||
|
||||
/**
|
||||
* This is an opaque data type representing an iterator instance.
|
||||
*/
|
||||
typedef struct qb_map_iter qb_map_iter_t;
|
||||
|
||||
#define QB_MAP_NOTIFY_DELETED 1
|
||||
#define QB_MAP_NOTIFY_REPLACED 2
|
||||
#define QB_MAP_NOTIFY_INSERTED 4
|
||||
#define QB_MAP_NOTIFY_RECURSIVE 8
|
||||
#define QB_MAP_NOTIFY_FREE 16
|
||||
|
||||
typedef void (*qb_map_notify_fn)(uint32_t event,
|
||||
char* key,
|
||||
void* old_value,
|
||||
void* value,
|
||||
void* user_data);
|
||||
|
||||
typedef int32_t (*qb_map_transverse_fn)(const char* key,
|
||||
void* value,
|
||||
void* user_data);
|
||||
|
||||
/**
|
||||
* Create an unsorted map based on a hashtable.
|
||||
*
|
||||
* @param max_size maximum size of the hashtable
|
||||
*
|
||||
* @return the map instance
|
||||
*/
|
||||
qb_map_t* qb_hashtable_create(size_t max_size);
|
||||
|
||||
/**
|
||||
* Create a sorted map using a skiplist.
|
||||
*
|
||||
* @return the map instance
|
||||
*/
|
||||
qb_map_t* qb_skiplist_create(void);
|
||||
|
||||
/**
|
||||
* Create a sorted map using a Patricia trie or "Radix tree".
|
||||
*
|
||||
* @htmlonly
|
||||
* See the wikipedia <a href="http://en.wikipedia.org/wiki/Radix_Tree">Radix_tree</a>
|
||||
* and <a href="http://en.wikipedia.org/wiki/Trie">Trie</a> pages.
|
||||
* @endhtmlonly
|
||||
*/
|
||||
qb_map_t* qb_trie_create(void);
|
||||
|
||||
/**
|
||||
* print out the nodes in the trie
|
||||
*
|
||||
* (for debug purposes)
|
||||
*/
|
||||
void
|
||||
qb_trie_dump(qb_map_t* m);
|
||||
|
||||
/**
|
||||
* Add a notifier to the map.
|
||||
*
|
||||
* @param m the map instance
|
||||
* @param key the key (or prefix) to attach the notification to.
|
||||
* @param fn the callback
|
||||
* @param events the type of events to register for.
|
||||
* @param user_data a pointer to be passed into the callback
|
||||
*
|
||||
* @note QB_MAP_NOTIFY_INSERTED is only valid on tries.
|
||||
* @note you can use key prefixes with trie maps.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval -errno failure
|
||||
*/
|
||||
int32_t qb_map_notify_add(qb_map_t* m, const char* key,
|
||||
qb_map_notify_fn fn, int32_t events,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Delete a notifier from the map.
|
||||
*
|
||||
* @note the key,fn and events must match those you added.
|
||||
*
|
||||
* @param m the map instance
|
||||
* @param key the key (or prefix) to attach the notification to.
|
||||
* @param fn the callback
|
||||
* @param events the type of events to register for.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval -errno failure
|
||||
*/
|
||||
int32_t qb_map_notify_del(qb_map_t* m, const char* key,
|
||||
qb_map_notify_fn fn, int32_t events);
|
||||
|
||||
/**
|
||||
* Delete a notifier from the map (including the userdata).
|
||||
*
|
||||
* @note the key, fn, events and userdata must match those you added.
|
||||
*
|
||||
* @param m the map instance
|
||||
* @param key the key (or prefix) to attach the notification to.
|
||||
* @param fn the callback
|
||||
* @param events the type of events to register for.
|
||||
* @param user_data a pointer to be passed into the callback
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval -errno failure
|
||||
*/
|
||||
int32_t qb_map_notify_del_2(qb_map_t* m, const char* key,
|
||||
qb_map_notify_fn fn, int32_t events,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Inserts a new key and value into a qb_map_t.
|
||||
*
|
||||
* If the key already exists in the qb_map_t, it gets replaced by the new key.
|
||||
*/
|
||||
void qb_map_put(qb_map_t *map, const char* key, const void* value);
|
||||
|
||||
/**
|
||||
* Gets the value corresponding to the given key.
|
||||
*
|
||||
* @retval NULL (if the key does not exist)
|
||||
* @retval a pointer to the value
|
||||
*/
|
||||
void* qb_map_get(qb_map_t *map, const char* key);
|
||||
|
||||
/**
|
||||
* Removes a key/value pair from a map.
|
||||
*/
|
||||
int32_t qb_map_rm(qb_map_t *map, const char* key);
|
||||
|
||||
/**
|
||||
* Get the number of items in the map.
|
||||
*/
|
||||
size_t qb_map_count_get(qb_map_t *map);
|
||||
|
||||
/**
|
||||
* Calls the given function for each of the key/value pairs in the map.
|
||||
*
|
||||
* The function is passed the key and value of each pair, and the given data
|
||||
* parameter. The map is traversed in sorted order.
|
||||
*/
|
||||
void qb_map_foreach(qb_map_t *map, qb_map_transverse_fn func, void* user_data);
|
||||
|
||||
/**
|
||||
* Create an iterator
|
||||
*/
|
||||
qb_map_iter_t* qb_map_iter_create(qb_map_t *map);
|
||||
|
||||
/**
|
||||
* Create a prefix iterator.
|
||||
*
|
||||
* This will iterate over all items with the given
|
||||
* prefix.
|
||||
* @note this is only supported by the trie.
|
||||
*/
|
||||
qb_map_iter_t* qb_map_pref_iter_create(qb_map_t *map, const char* prefix);
|
||||
|
||||
/**
|
||||
* Get the next item
|
||||
*
|
||||
* @param i the iterator
|
||||
* @param value (out) the next item's value
|
||||
*
|
||||
* @retval the next key
|
||||
* @retval NULL - the end of the iteration
|
||||
*/
|
||||
const char* qb_map_iter_next(qb_map_iter_t* i, void** value);
|
||||
|
||||
/**
|
||||
* free the iterator
|
||||
*
|
||||
* @param i the iterator
|
||||
*/
|
||||
void qb_map_iter_free(qb_map_iter_t* i);
|
||||
|
||||
/**
|
||||
* Destroy the map, removes all the items from the map.
|
||||
*/
|
||||
void qb_map_destroy(qb_map_t *map);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* QB_MAP_H_DEFINED */
|
||||
288
include/qb/qbrb.h
Normal file
288
include/qb/qbrb.h
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QB_RB_H_DEFINED
|
||||
#define QB_RB_H_DEFINED
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @file qbrb.h
|
||||
* This implements a ring buffer that works in "chunks" not bytes.
|
||||
* So you write/read a complete chunk or not at all.
|
||||
* There are two types of ring buffer normal and overwrite.
|
||||
* Overwrite will reclaim the oldest chunks inorder to make way for new ones,
|
||||
* the normal version will refuse to write a new chunk if the ring buffer
|
||||
* is full.
|
||||
*
|
||||
* This implementation is capable of working across processes, but one process
|
||||
* must only write and the other prrocess read.
|
||||
*
|
||||
* The read process will do the following:
|
||||
* @code
|
||||
* rb = qb_rb_open("test2", 2000, QB_RB_FLAG_SHARED_PROCESS|QB_RB_FLAG_CREATE);
|
||||
* for (i = 0; i < 200; i++) {
|
||||
* try_read_again:
|
||||
* l = qb_rb_chunk_read(rb, (void *)out, 32, 1000);
|
||||
* if (l < 0) {
|
||||
* goto try_read_again;
|
||||
* }
|
||||
* }
|
||||
* ...
|
||||
* qb_rb_close(rb);
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* The write process will do the following:
|
||||
* @code
|
||||
* rb = qb_rb_open("test2", 2000, QB_RB_FLAG_SHARED_PROCESS);
|
||||
* for (i = 0; i < 200; i++) {
|
||||
* try_write_again:
|
||||
* l = qb_rb_chunk_write(rb, &v, sizeof(v));
|
||||
* if (l < sizeof(v)) {
|
||||
* goto try_write_again;
|
||||
* }
|
||||
* }
|
||||
* ...
|
||||
* qb_rb_close(rb);
|
||||
* @endcode
|
||||
*
|
||||
* @author Angus Salkeld <asalkeld@redhat.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* create a ring buffer (rather than open and existing one)
|
||||
* @see qb_rb_open()
|
||||
*/
|
||||
#define QB_RB_FLAG_CREATE 0x01
|
||||
/**
|
||||
* New calls to qb_rb_chunk_write() will call qb_rb_chunk_reclaim()
|
||||
* if there is not enough space.
|
||||
* If this is not set then new writes will be refused.
|
||||
* @see qb_rb_open()
|
||||
*/
|
||||
#define QB_RB_FLAG_OVERWRITE 0x02
|
||||
/**
|
||||
* The ringbuffer will be shared between pthreads not processes.
|
||||
* This effects the type of locks/semaphores that are used.
|
||||
* @see qb_rb_open()
|
||||
*/
|
||||
#define QB_RB_FLAG_SHARED_THREAD 0x04
|
||||
/**
|
||||
* The ringbuffer will be shared between processes.
|
||||
* This effects the type of locks/semaphores that are used.
|
||||
* @see qb_rb_open()
|
||||
*/
|
||||
#define QB_RB_FLAG_SHARED_PROCESS 0x08
|
||||
|
||||
struct qb_ringbuffer_s;
|
||||
typedef struct qb_ringbuffer_s qb_ringbuffer_t;
|
||||
|
||||
/**
|
||||
* Create the ring buffer with the given type.
|
||||
*
|
||||
* This creates allocates a ring buffer in shared memory.
|
||||
*
|
||||
* @param name the unique name of this ringbuffer.
|
||||
* @param size the requested size.
|
||||
* @param flags or'ed flags
|
||||
* @param shared_user_data_size size for a shared data area.
|
||||
* @note the actual size will be rounded up to the next page size.
|
||||
* @return a new ring buffer or NULL if there was a problem.
|
||||
* @see QB_RB_FLAG_CREATE, QB_RB_FLAG_OVERWRITE, QB_RB_FLAG_SHARED_THREAD, QB_RB_FLAG_SHARED_PROCESS
|
||||
*/
|
||||
qb_ringbuffer_t *qb_rb_open(const char *name, size_t size, uint32_t flags,
|
||||
size_t shared_user_data_size);
|
||||
|
||||
/**
|
||||
* Dereference the ringbuffer and if we are the last user destroy it.
|
||||
*
|
||||
* All files, mmaped memory, semaphores and locks will be destroyed.
|
||||
*
|
||||
* @param rb ringbuffer instance
|
||||
*/
|
||||
void qb_rb_close(qb_ringbuffer_t * rb);
|
||||
|
||||
/**
|
||||
* Get the name of the ringbuffer.
|
||||
* @param rb ringbuffer instance
|
||||
* @return name.
|
||||
*/
|
||||
char *qb_rb_name_get(qb_ringbuffer_t * rb);
|
||||
|
||||
/**
|
||||
* Get a point to user shared data area.
|
||||
*
|
||||
* @note this is of size "shared_user_data_size" passed into qb_rb_open()
|
||||
*
|
||||
* @param rb ringbuffer instance
|
||||
* @return pointer to shared data.
|
||||
*/
|
||||
void *qb_rb_shared_user_data_get(qb_ringbuffer_t * rb);
|
||||
|
||||
/**
|
||||
* Write a chunk to the ring buffer.
|
||||
*
|
||||
* This simply calls qb_rb_chunk_alloc() and then
|
||||
* qb_rb_chunk_commit().
|
||||
*
|
||||
* @param rb ringbuffer instance
|
||||
* @param data (in) the data to write
|
||||
* @param len (in) the size of the chunk.
|
||||
* @return the amount of bytes actually buffered (either len or -1).
|
||||
*
|
||||
* @see qb_rb_chunk_alloc()
|
||||
* @see qb_rb_chunk_commit()
|
||||
*/
|
||||
ssize_t qb_rb_chunk_write(qb_ringbuffer_t * rb, const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* Allocate space for a chunk of the given size.
|
||||
*
|
||||
* If type == QB_RB_FLAG_OVERWRITE then this will always return non-null
|
||||
* but if it's type is QB_RB_NORMAL then when there is not enough space then
|
||||
* it will return NULL.
|
||||
*
|
||||
* @param rb ringbuffer instance
|
||||
* @param len (in) the size to allocate.
|
||||
* @return pointer to chunk to write to, or NULL (if no space).
|
||||
*
|
||||
* @see qb_rb_chunk_alloc()
|
||||
*/
|
||||
void *qb_rb_chunk_alloc(qb_ringbuffer_t * rb, size_t len);
|
||||
|
||||
/**
|
||||
* finalize the chunk.
|
||||
* @param rb ringbuffer instance
|
||||
* @param len (in) the size of the chunk.
|
||||
*/
|
||||
int32_t qb_rb_chunk_commit(qb_ringbuffer_t * rb, size_t len);
|
||||
|
||||
/**
|
||||
* Read (without reclaiming) the last chunk.
|
||||
*
|
||||
* This function is a way of accessing the next chunk without a memcpy().
|
||||
* You can read the chunk data in place.
|
||||
*
|
||||
* @note This function will not "pop" the chunk, you will need to call
|
||||
* qb_rb_chunk_reclaim().
|
||||
* @param rb ringbuffer instance
|
||||
* @param data_out (out) a pointer to the next chunk to read (not copied).
|
||||
* @param ms_timeout (in) time to wait for new data.
|
||||
*
|
||||
* @return the size of the chunk (0 if buffer empty).
|
||||
*/
|
||||
ssize_t qb_rb_chunk_peek(qb_ringbuffer_t * rb, void **data_out,
|
||||
int32_t ms_timeout);
|
||||
|
||||
/**
|
||||
* Reclaim the oldest chunk.
|
||||
* You will need to call this if using qb_rb_chunk_peek().
|
||||
* @param rb ringbuffer instance
|
||||
*/
|
||||
void qb_rb_chunk_reclaim(qb_ringbuffer_t * rb);
|
||||
|
||||
/**
|
||||
* Read the oldest chunk into data_out.
|
||||
*
|
||||
* This is the same as qb_rb_chunk_peek() memcpy() and qb_rb_chunk_reclaim().
|
||||
*
|
||||
* @param rb ringbuffer instance
|
||||
* @param data_out (in/out) the chunk will be memcpy'ed into this.
|
||||
* @param len (in) the size of data_out.
|
||||
* @param ms_timeout the amount od time to wait for new data.
|
||||
* @return the size of the chunk, or error.
|
||||
*/
|
||||
ssize_t qb_rb_chunk_read(qb_ringbuffer_t * rb, void *data_out, size_t len,
|
||||
int32_t ms_timeout);
|
||||
|
||||
/**
|
||||
* Get the reference count.
|
||||
*
|
||||
* @param rb ringbuffer instance
|
||||
* @return the number of references
|
||||
*/
|
||||
int32_t qb_rb_refcount_get(qb_ringbuffer_t * rb);
|
||||
|
||||
/**
|
||||
* The amount of free space in the ring buffer.
|
||||
*
|
||||
* @note Some of this space will be consumed by the chunk headers.
|
||||
* @param rb ringbuffer instance
|
||||
*/
|
||||
ssize_t qb_rb_space_free(qb_ringbuffer_t * rb);
|
||||
|
||||
/**
|
||||
* The total amount of data in the buffer.
|
||||
*
|
||||
* @note This includes the chunk headers (8 bytes per chunk).
|
||||
* @param rb ringbuffer instance
|
||||
*/
|
||||
ssize_t qb_rb_space_used(qb_ringbuffer_t * rb);
|
||||
|
||||
/**
|
||||
* The total number of chunks in the buffer.
|
||||
*
|
||||
* @param rb ringbuffer instance
|
||||
*/
|
||||
ssize_t qb_rb_chunks_used(qb_ringbuffer_t * rb);
|
||||
|
||||
/**
|
||||
* Write the contents of the Ring Buffer to file.
|
||||
* @param fd open file to write the ringbuffer data to.
|
||||
* @param rb ringbuffer instance
|
||||
* @see qb_rb_create_from_file()
|
||||
*/
|
||||
ssize_t qb_rb_write_to_file(qb_ringbuffer_t * rb, int32_t fd);
|
||||
|
||||
/**
|
||||
* Load the saved ring buffer from file into tempory memory.
|
||||
* @param fd file with saved ringbuffer data.
|
||||
* @param flags same flags as passed into qb_rb_open()
|
||||
* @return new ringbuffer instance
|
||||
* @see qb_rb_write_to_file()
|
||||
*/
|
||||
qb_ringbuffer_t *qb_rb_create_from_file(int32_t fd, uint32_t flags);
|
||||
|
||||
/**
|
||||
* Like 'chown' it changes the owner and group of the ringbuffers
|
||||
* resources.
|
||||
* @param owner uid of the owner to change to
|
||||
* @param group gid of the group to change to
|
||||
* @param rb ringbuffer instance
|
||||
* @return status (0 = ok, -errno for error)
|
||||
*/
|
||||
int32_t qb_rb_chown(qb_ringbuffer_t * rb, uid_t owner, gid_t group);
|
||||
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* QB_RB_H_DEFINED */
|
||||
298
include/qb/qbutil.h
Normal file
298
include/qb/qbutil.h
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QB_UTIL_H_DEFINED
|
||||
#define QB_UTIL_H_DEFINED
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef S_SPLINT_S
|
||||
#include <unistd.h>
|
||||
#endif /* S_SPLINT_S */
|
||||
#include <qb/qbdefs.h>
|
||||
|
||||
/**
|
||||
* @file qbutil.h
|
||||
* @author Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* These are some convience functions used throughout libqb.
|
||||
*
|
||||
* @par Locking
|
||||
* - qb_thread_lock_create()
|
||||
* - qb_thread_lock()
|
||||
* - qb_thread_trylock()
|
||||
* - qb_thread_unlock()
|
||||
* - qb_thread_lock_destroy()
|
||||
*
|
||||
* @par Time functions
|
||||
* - qb_timespec_add_ms()
|
||||
* - qb_util_nano_current_get()
|
||||
* - qb_util_nano_monotonic_hz()
|
||||
* - qb_util_nano_from_epoch_get()
|
||||
* - qb_util_timespec_from_epoch_get()
|
||||
*
|
||||
* @par Basic Stopwatch
|
||||
* @code
|
||||
* uint64_t elapsed1;
|
||||
* uint64_t elapsed2;
|
||||
* qb_util_stopwatch_t *sw = qb_util_stopwatch_create();
|
||||
*
|
||||
* qb_util_stopwatch_start(sw);
|
||||
*
|
||||
* usleep(sometime);
|
||||
* qb_util_stopwatch_stop(sw);
|
||||
* elapsed1 = qb_util_stopwatch_us_elapsed_get(sw);
|
||||
*
|
||||
* usleep(somemoretime);
|
||||
* qb_util_stopwatch_stop(sw);
|
||||
* elapsed2 = qb_util_stopwatch_us_elapsed_get(sw);
|
||||
*
|
||||
* qb_util_stopwatch_free(sw);
|
||||
* @endcode
|
||||
*
|
||||
* @par Stopwatch with splits
|
||||
* Setup a stopwatch with space for 3 splits.
|
||||
*
|
||||
* @code
|
||||
* uint64_t split;
|
||||
* qb_util_stopwatch_t *sw = qb_util_stopwatch_create();
|
||||
*
|
||||
* qb_util_stopwatch_split_ctl(sw, 3, 0);
|
||||
* qb_util_stopwatch_start(sw);
|
||||
*
|
||||
* usleep(sometime);
|
||||
* qb_util_stopwatch_split(sw);
|
||||
*
|
||||
* usleep(somemoretime);
|
||||
* qb_util_stopwatch_split(sw);
|
||||
*
|
||||
* usleep(somemoretime);
|
||||
* qb_util_stopwatch_split(sw);
|
||||
*
|
||||
* idx = qb_util_stopwatch_split_last(sw);
|
||||
* do {
|
||||
* split = qb_util_stopwatch_time_split_get(sw, idx, idx);
|
||||
* qb_log(LOG_INFO, "split %d is %"PRIu64"", last, split);
|
||||
* idx--;
|
||||
* } while (split > 0);
|
||||
*
|
||||
* split = qb_util_stopwatch_time_split_get(sw, 2, 1);
|
||||
* qb_log(LOG_INFO, "time between second and third split is %"PRIu64"", split);
|
||||
*
|
||||
* qb_util_stopwatch_free(sw);
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef qb_thread_lock_type_t
|
||||
* QB_THREAD_LOCK_SHORT is a short term lock (spinlock if available on your system)
|
||||
* QB_THREAD_LOCK_LONG is a mutex
|
||||
*/
|
||||
typedef enum {
|
||||
QB_THREAD_LOCK_SHORT,
|
||||
QB_THREAD_LOCK_LONG,
|
||||
} qb_thread_lock_type_t;
|
||||
|
||||
struct qb_thread_lock_s;
|
||||
typedef struct qb_thread_lock_s qb_thread_lock_t;
|
||||
|
||||
/**
|
||||
* Create a new lock of the given type.
|
||||
* @param type QB_THREAD_LOCK_SHORT == spinlock (where available, else mutex)
|
||||
* QB_THREAD_LOCK_LONG == mutex
|
||||
* @return pointer to qb_thread_lock_type_t or NULL on error.
|
||||
*/
|
||||
qb_thread_lock_t *qb_thread_lock_create(qb_thread_lock_type_t type);
|
||||
|
||||
/**
|
||||
* Calls either pthread_mutex_lock() or pthread_spin_lock().
|
||||
*/
|
||||
int32_t qb_thread_lock(qb_thread_lock_t * tl);
|
||||
|
||||
/**
|
||||
* Calls either pthread_mutex_trylock() or pthread_spin_trylock().
|
||||
*/
|
||||
int32_t qb_thread_trylock(qb_thread_lock_t * tl);
|
||||
|
||||
/**
|
||||
* Calls either pthread_mutex_unlock() or pthread_spin_unlock.
|
||||
*/
|
||||
int32_t qb_thread_unlock(qb_thread_lock_t * tl);
|
||||
|
||||
/**
|
||||
* Calls either pthread_mutex_destro() or pthread_spin_destroy().
|
||||
*/
|
||||
int32_t qb_thread_lock_destroy(qb_thread_lock_t * tl);
|
||||
|
||||
typedef void (*qb_util_log_fn_t) (const char *file_name,
|
||||
int32_t file_line,
|
||||
int32_t severity, const char *msg);
|
||||
|
||||
/**
|
||||
* Use this function to output libqb internal log message as you wish.
|
||||
*/
|
||||
void qb_util_set_log_function(qb_util_log_fn_t fn) QB_GNUC_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Add milliseconds onto the timespec.
|
||||
* @param ts the ts to add to
|
||||
* @param ms the amount of milliseconds to increment ts
|
||||
*/
|
||||
void qb_timespec_add_ms(struct timespec *ts, int32_t ms);
|
||||
|
||||
/**
|
||||
* Get the current number of nano secounds produced
|
||||
* by the systems incrementing clock (CLOCK_MONOTOMIC
|
||||
* if available).
|
||||
*/
|
||||
uint64_t qb_util_nano_current_get(void);
|
||||
|
||||
/**
|
||||
* Get the frequence of the clock used in
|
||||
* qb_util_nano_current_get().
|
||||
*/
|
||||
uint64_t qb_util_nano_monotonic_hz(void);
|
||||
|
||||
/**
|
||||
* Get the time in nano seconds since epoch.
|
||||
*/
|
||||
uint64_t qb_util_nano_from_epoch_get(void);
|
||||
|
||||
/**
|
||||
* Get the time in timespec since epoch.
|
||||
* @param ts (out) the timespec
|
||||
* @return status (0 == ok, -errno on error)
|
||||
*/
|
||||
void qb_util_timespec_from_epoch_get(struct timespec *ts);
|
||||
|
||||
/**
|
||||
* strerror_r replacement.
|
||||
*/
|
||||
char *qb_strerror_r(int errnum, char *buf, size_t buflen);
|
||||
|
||||
|
||||
typedef struct qb_util_stopwatch qb_util_stopwatch_t;
|
||||
|
||||
#define QB_UTIL_SW_OVERWRITE 0x01
|
||||
|
||||
|
||||
/**
|
||||
* Create a Stopwatch (to time operations)
|
||||
*/
|
||||
qb_util_stopwatch_t * qb_util_stopwatch_create(void);
|
||||
|
||||
/**
|
||||
* Free the stopwatch
|
||||
*/
|
||||
void qb_util_stopwatch_free(qb_util_stopwatch_t *sw);
|
||||
|
||||
/**
|
||||
* Start the stopwatch
|
||||
*
|
||||
* This also acts as a reset. Essentially it sets the
|
||||
* starting time and clears the splits.
|
||||
*/
|
||||
void qb_util_stopwatch_start(qb_util_stopwatch_t *sw);
|
||||
|
||||
/**
|
||||
* Stop the stopwatch
|
||||
*
|
||||
* This just allows you to get the elapsed time. So
|
||||
* you can call this multiple times. Do not call qb_util_stopwatch_start()
|
||||
* unless you want to reset the stopwatch.
|
||||
*/
|
||||
void qb_util_stopwatch_stop(qb_util_stopwatch_t *sw);
|
||||
|
||||
/**
|
||||
* Get the elapsed time in micro seconds.
|
||||
*
|
||||
* (it must have been started and stopped).
|
||||
*/
|
||||
uint64_t qb_util_stopwatch_us_elapsed_get(qb_util_stopwatch_t *sw);
|
||||
|
||||
/**
|
||||
* Get the elapsed time in seconds.
|
||||
*
|
||||
* (it must have been started and stopped).
|
||||
*/
|
||||
float qb_util_stopwatch_sec_elapsed_get(qb_util_stopwatch_t *sw);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sw the stopwatch
|
||||
* @param max_splits maximum number of time splits
|
||||
* @param options (0 or QB_UTIL_SW_OVERWRITE )
|
||||
* @retval 0 on success
|
||||
* @retval -errno on failure
|
||||
*/
|
||||
int32_t qb_util_stopwatch_split_ctl(qb_util_stopwatch_t *sw,
|
||||
uint32_t max_splits, uint32_t options);
|
||||
|
||||
/**
|
||||
* Create a new time split (or lap time)
|
||||
*
|
||||
* @param sw the stopwatch
|
||||
* @retval the relative split time in micro seconds
|
||||
* @retval 0 if no more splits available
|
||||
*/
|
||||
uint64_t qb_util_stopwatch_split(qb_util_stopwatch_t *sw);
|
||||
|
||||
/**
|
||||
* Get the last split index to be used by
|
||||
* qb_util_stopwatch_time_split_get()
|
||||
*
|
||||
* @note this is zero based
|
||||
*
|
||||
* @param sw the stopwatch
|
||||
* @return the last entry index
|
||||
*/
|
||||
uint32_t
|
||||
qb_util_stopwatch_split_last(qb_util_stopwatch_t *sw);
|
||||
|
||||
/**
|
||||
* Read the time split (in us) from "receint" to "older".
|
||||
*
|
||||
* If older == receint then the cumulated split will be
|
||||
* returned (from the stopwatch start).
|
||||
*
|
||||
* @param sw the stopwatch
|
||||
* @param receint split
|
||||
* @param older split
|
||||
* @retval the split time in micro seconds
|
||||
* @retval 0 if not a valid split
|
||||
*/
|
||||
uint64_t
|
||||
qb_util_stopwatch_time_split_get(qb_util_stopwatch_t *sw,
|
||||
uint32_t receint, uint32_t older);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* QB_UTIL_H_DEFINED */
|
||||
230
include/tlist.h
Normal file
230
include/tlist.h
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007, 2009 Red Hat, Inc.
|
||||
*
|
||||
* Author: Steven Dake <sdake@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QB_TLIST_H_DEFINED
|
||||
#define QB_TLIST_H_DEFINED
|
||||
|
||||
#include "os_base.h"
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbutil.h>
|
||||
#include <qb/qblist.h>
|
||||
|
||||
#ifndef TIMER_HANDLE
|
||||
typedef void *timer_handle;
|
||||
#define TIMER_HANDLE
|
||||
#endif
|
||||
|
||||
static int64_t timerlist_hertz = HZ;
|
||||
|
||||
struct timerlist {
|
||||
struct qb_list_head timer_head;
|
||||
struct qb_list_head *timer_iter;
|
||||
};
|
||||
|
||||
struct timerlist_timer {
|
||||
struct qb_list_head list;
|
||||
uint64_t expire_time;
|
||||
int32_t is_absolute_timer;
|
||||
void (*timer_fn) (void *data);
|
||||
void *data;
|
||||
timer_handle handle_addr;
|
||||
};
|
||||
|
||||
static inline void timerlist_init(struct timerlist *timerlist)
|
||||
{
|
||||
qb_list_init(&timerlist->timer_head);
|
||||
timerlist_hertz = qb_util_nano_monotonic_hz();
|
||||
}
|
||||
|
||||
static inline void timerlist_add(struct timerlist *timerlist,
|
||||
struct timerlist_timer *timer)
|
||||
{
|
||||
struct qb_list_head *timer_list = 0;
|
||||
struct timerlist_timer *timer_from_list;
|
||||
int32_t found;
|
||||
|
||||
for (found = 0, timer_list = timerlist->timer_head.next;
|
||||
timer_list != &timerlist->timer_head;
|
||||
timer_list = timer_list->next) {
|
||||
|
||||
timer_from_list = qb_list_entry(timer_list,
|
||||
struct timerlist_timer, list);
|
||||
|
||||
if (timer_from_list->expire_time > timer->expire_time) {
|
||||
qb_list_add(&timer->list, timer_list->prev);
|
||||
found = 1;
|
||||
break; /* for timer iteration */
|
||||
}
|
||||
}
|
||||
if (found == 0) {
|
||||
qb_list_add(&timer->list, timerlist->timer_head.prev);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int32_t timerlist_add_duration(struct timerlist *timerlist,
|
||||
void (*timer_fn) (void *data),
|
||||
void *data,
|
||||
uint64_t nano_duration,
|
||||
timer_handle * handle)
|
||||
{
|
||||
struct timerlist_timer *timer;
|
||||
|
||||
timer =
|
||||
(struct timerlist_timer *)malloc(sizeof(struct timerlist_timer));
|
||||
if (timer == 0) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
timer->expire_time = qb_util_nano_current_get() + nano_duration;
|
||||
timer->is_absolute_timer = 0;
|
||||
timer->data = data;
|
||||
timer->timer_fn = timer_fn;
|
||||
timer->handle_addr = handle;
|
||||
timerlist_add(timerlist, timer);
|
||||
|
||||
*handle = timer;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline void timerlist_del(struct timerlist *timerlist,
|
||||
timer_handle _timer_handle)
|
||||
{
|
||||
struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle;
|
||||
|
||||
memset(timer->handle_addr, 0, sizeof(struct timerlist_timer *));
|
||||
/*
|
||||
* If the next timer after the currently expiring timer because
|
||||
* timerlist_del is called from a timer handler, get to the next
|
||||
* timer
|
||||
*/
|
||||
if (timerlist->timer_iter == &timer->list) {
|
||||
timerlist->timer_iter = timerlist->timer_iter->next;
|
||||
}
|
||||
qb_list_del(&timer->list);
|
||||
qb_list_init(&timer->list);
|
||||
free(timer);
|
||||
}
|
||||
|
||||
static inline uint64_t timerlist_expire_time(struct timerlist
|
||||
*timerlist,
|
||||
timer_handle
|
||||
_timer_handle)
|
||||
{
|
||||
struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle;
|
||||
|
||||
return (timer->expire_time);
|
||||
}
|
||||
|
||||
static inline void timerlist_pre_dispatch(struct timerlist *timerlist,
|
||||
timer_handle _timer_handle)
|
||||
{
|
||||
struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle;
|
||||
|
||||
memset(timer->handle_addr, 0, sizeof(struct timerlist_timer *));
|
||||
qb_list_del(&timer->list);
|
||||
qb_list_init(&timer->list);
|
||||
}
|
||||
|
||||
static inline void timerlist_post_dispatch(struct timerlist *timerlist,
|
||||
timer_handle _timer_handle)
|
||||
{
|
||||
struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle;
|
||||
|
||||
free(timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the number of msec until the next timer will expire for use with poll
|
||||
*/
|
||||
static inline uint64_t timerlist_msec_duration_to_expire(struct timerlist *timerlist)
|
||||
{
|
||||
struct timerlist_timer *timer_from_list;
|
||||
volatile uint64_t current_time;
|
||||
volatile uint64_t msec_duration_to_expire;
|
||||
|
||||
/*
|
||||
* empty list, no expire
|
||||
*/
|
||||
if (timerlist->timer_head.next == &timerlist->timer_head) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
timer_from_list = qb_list_entry(timerlist->timer_head.next,
|
||||
struct timerlist_timer, list);
|
||||
|
||||
if (timer_from_list->is_absolute_timer) {
|
||||
current_time = qb_util_nano_from_epoch_get();
|
||||
} else {
|
||||
current_time = qb_util_nano_current_get();
|
||||
}
|
||||
|
||||
/*
|
||||
* timer at head of list is expired, zero msecs required
|
||||
*/
|
||||
if (timer_from_list->expire_time < current_time) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
msec_duration_to_expire =
|
||||
((timer_from_list->expire_time -
|
||||
current_time) / QB_TIME_NS_IN_MSEC) + (1000 / timerlist_hertz);
|
||||
return (msec_duration_to_expire);
|
||||
}
|
||||
|
||||
/*
|
||||
* Expires any timers that should be expired
|
||||
*/
|
||||
static inline void timerlist_expire(struct timerlist *timerlist)
|
||||
{
|
||||
struct timerlist_timer *timer_from_list;
|
||||
uint64_t current_time_from_epoch;
|
||||
uint64_t current_monotonic_time;
|
||||
uint64_t current_time;
|
||||
|
||||
current_monotonic_time = qb_util_nano_current_get();
|
||||
current_time_from_epoch = current_time = qb_util_nano_from_epoch_get();
|
||||
|
||||
for (timerlist->timer_iter = timerlist->timer_head.next;
|
||||
timerlist->timer_iter != &timerlist->timer_head;) {
|
||||
|
||||
timer_from_list = qb_list_entry(timerlist->timer_iter,
|
||||
struct timerlist_timer, list);
|
||||
|
||||
current_time =
|
||||
(timer_from_list->
|
||||
is_absolute_timer ? current_time_from_epoch :
|
||||
current_monotonic_time);
|
||||
|
||||
if (timer_from_list->expire_time < current_time) {
|
||||
timerlist->timer_iter = timerlist->timer_iter->next;
|
||||
|
||||
timerlist_pre_dispatch(timerlist, timer_from_list);
|
||||
|
||||
timer_from_list->timer_fn(timer_from_list->data);
|
||||
|
||||
timerlist_post_dispatch(timerlist, timer_from_list);
|
||||
} else {
|
||||
break; /* for timer iteration */
|
||||
}
|
||||
}
|
||||
timerlist->timer_iter = 0;
|
||||
}
|
||||
#endif /* QB_TLIST_H_DEFINED */
|
||||
527
install-sh
Executable file
527
install-sh
Executable file
@ -0,0 +1,527 @@
|
||||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2011-01-19.21; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
nl='
|
||||
'
|
||||
IFS=" "" $nl"
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit=${DOITPROG-}
|
||||
if test -z "$doit"; then
|
||||
doit_exec=exec
|
||||
else
|
||||
doit_exec=$doit
|
||||
fi
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_glob='?'
|
||||
initialize_posix_glob='
|
||||
test "$posix_glob" != "?" || {
|
||||
if (set -f) 2>/dev/null; then
|
||||
posix_glob=
|
||||
else
|
||||
posix_glob=:
|
||||
fi
|
||||
}
|
||||
'
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
no_target_directory=
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *' '* | *'
|
||||
'* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t) dst_arg=$2
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) no_target_directory=true;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call `install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test -n "$no_target_directory"; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
# Prefer dirname, but fall back on a substitute if dirname fails.
|
||||
dstdir=`
|
||||
(dirname "$dst") 2>/dev/null ||
|
||||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$dst" : 'X\(//\)[^/]' \| \
|
||||
X"$dst" : 'X\(//\)$' \| \
|
||||
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
||||
echo X"$dst" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)[^/].*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\).*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
s/.*/./; q'
|
||||
`
|
||||
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writeable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
eval "$initialize_posix_glob"
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
$posix_glob set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
$posix_glob set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
|
||||
eval "$initialize_posix_glob" &&
|
||||
$posix_glob set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
$posix_glob set +f &&
|
||||
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
81
lib/Makefile.am
Normal file
81
lib/Makefile.am
Normal file
@ -0,0 +1,81 @@
|
||||
#
|
||||
# Copyright (C) 2010 Red Hat, Inc.
|
||||
#
|
||||
# Author: Angus Salkeld <asaslkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
noinst_HEADERS = ipc_int.h util_int.h ringbuffer_int.h loop_int.h log_int.h map_int.h
|
||||
|
||||
#
|
||||
# Here are a set of rules to help you update your library version information:
|
||||
# Start with version information of ‘0:0:0’ for each libtool library.
|
||||
# Update the version information only immediately before a public release of your software.
|
||||
# More frequent updates are unnecessary, and only guarantee that the current interface number gets larger faster.
|
||||
# If the library source code has changed at all since the last update, then increment revision (‘c:r:a’ becomes ‘c:r+1:a’).
|
||||
# If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0.
|
||||
# If any interfaces have been added since the last public release, then increment age.
|
||||
# If any interfaces have been removed since the last public release, then set age to 0.
|
||||
#
|
||||
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
|
||||
lib_LTLIBRARIES = libqb.la
|
||||
|
||||
libqb_la_LDFLAGS = -version-info 11:1:11
|
||||
source_to_lint = util.c hdb.c ringbuffer.c ringbuffer_helper.c array.c \
|
||||
loop.c loop_poll.c loop_job.c loop_timerlist.c \
|
||||
ipcc.c ipcs.c ipc_shm.c ipc_us.c \
|
||||
log.c log_thread.c log_blackbox.c log_file.c \
|
||||
log_syslog.c log_dcs.c log_format.c \
|
||||
map.c skiplist.c hashtable.c trie.c
|
||||
|
||||
libqb_la_SOURCES = $(source_to_lint) unix.c
|
||||
libqb_la_LIBADD = @LTLIBOBJS@
|
||||
|
||||
if HAVE_SYSV_MQ
|
||||
libqb_la_SOURCES+=ipc_sysv_mq.c
|
||||
endif
|
||||
|
||||
if HAVE_POSIX_MQ
|
||||
libqb_la_SOURCES+=ipc_posix_mq.c
|
||||
endif
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libqb.pc
|
||||
|
||||
if HAVE_SPLINT
|
||||
check_SCRIPTS = run_splint.sh
|
||||
TESTS = $(check_SCRIPTS)
|
||||
|
||||
ALL_LINT_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(libqb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CPPFLAGS) \
|
||||
$(LINT_FLAGS)
|
||||
|
||||
run_splint.sh: $(top_srcdir)/configure.ac
|
||||
echo "$(SPLINT) $(ALL_LINT_FLAGS) $(addprefix $(top_srcdir)/lib/, $(source_to_lint))" > $@
|
||||
$(AM_V_GEN)chmod +x $@
|
||||
|
||||
dist-clean-local:
|
||||
$(AM_V_GEN)rm -f run_splint.sh
|
||||
|
||||
clean-generic:
|
||||
$(AM_V_GEN)rm -f run_splint.sh
|
||||
endif
|
||||
|
||||
|
||||
942
lib/Makefile.in
Normal file
942
lib/Makefile.in
Normal file
@ -0,0 +1,942 @@
|
||||
# Makefile.in generated by automake 1.11.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
#
|
||||
# Copyright (C) 2010 Red Hat, Inc.
|
||||
#
|
||||
# Author: Angus Salkeld <asaslkeld@redhat.com>
|
||||
#
|
||||
# This file is part of libqb.
|
||||
#
|
||||
# libqb 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.
|
||||
#
|
||||
# libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
@HAVE_SYSV_MQ_TRUE@am__append_1 = ipc_sysv_mq.c
|
||||
@HAVE_POSIX_MQ_TRUE@am__append_2 = ipc_posix_mq.c
|
||||
subdir = lib
|
||||
DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in $(srcdir)/libqb.pc.in strchrnul.c \
|
||||
strlcat.c strlcpy.c
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/include/config.h \
|
||||
$(top_builddir)/include/qb/qbconfig.h
|
||||
CONFIG_CLEAN_FILES = libqb.pc
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)"
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||
libqb_la_DEPENDENCIES = @LTLIBOBJS@
|
||||
am__libqb_la_SOURCES_DIST = util.c hdb.c ringbuffer.c \
|
||||
ringbuffer_helper.c array.c loop.c loop_poll.c loop_job.c \
|
||||
loop_timerlist.c ipcc.c ipcs.c ipc_shm.c ipc_us.c log.c \
|
||||
log_thread.c log_blackbox.c log_file.c log_syslog.c log_dcs.c \
|
||||
log_format.c map.c skiplist.c hashtable.c trie.c unix.c \
|
||||
ipc_sysv_mq.c ipc_posix_mq.c
|
||||
am__objects_1 = util.lo hdb.lo ringbuffer.lo ringbuffer_helper.lo \
|
||||
array.lo loop.lo loop_poll.lo loop_job.lo loop_timerlist.lo \
|
||||
ipcc.lo ipcs.lo ipc_shm.lo ipc_us.lo log.lo log_thread.lo \
|
||||
log_blackbox.lo log_file.lo log_syslog.lo log_dcs.lo \
|
||||
log_format.lo map.lo skiplist.lo hashtable.lo trie.lo
|
||||
@HAVE_SYSV_MQ_TRUE@am__objects_2 = ipc_sysv_mq.lo
|
||||
@HAVE_POSIX_MQ_TRUE@am__objects_3 = ipc_posix_mq.lo
|
||||
am_libqb_la_OBJECTS = $(am__objects_1) unix.lo $(am__objects_2) \
|
||||
$(am__objects_3)
|
||||
libqb_la_OBJECTS = $(am_libqb_la_OBJECTS)
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||
am__v_lt_0 = --silent
|
||||
libqb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(libqb_la_LDFLAGS) $(LDFLAGS) -o $@
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include -I$(top_builddir)/include/qb
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
|
||||
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||||
$(AM_CFLAGS) $(CFLAGS)
|
||||
AM_V_CC = $(am__v_CC_@AM_V@)
|
||||
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
||||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
SOURCES = $(libqb_la_SOURCES)
|
||||
DIST_SOURCES = $(am__libqb_la_SOURCES_DIST)
|
||||
DATA = $(pkgconfig_DATA)
|
||||
HEADERS = $(noinst_HEADERS)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
# If stdout is a non-dumb tty, use colors. If test -t is not supported,
|
||||
# then this fails; a conservative approach. Of course do not redirect
|
||||
# stdout here, just stderr.
|
||||
am__tty_colors = \
|
||||
red=; grn=; lgn=; blu=; std=; \
|
||||
test "X$(AM_COLOR_TESTS)" != Xno \
|
||||
&& test "X$$TERM" != Xdumb \
|
||||
&& { test "X$(AM_COLOR_TESTS)" = Xalways || test -t 1 2>/dev/null; } \
|
||||
&& { \
|
||||
red='[0;31m'; \
|
||||
grn='[0;32m'; \
|
||||
lgn='[1;32m'; \
|
||||
blu='[1;34m'; \
|
||||
std='[m'; \
|
||||
}
|
||||
# Restructured Text title and section.
|
||||
am__rst_title = sed 's/.*/ & /;h;s/./=/g;p;x;p;g;p;s/.*//'
|
||||
am__rst_section = sed 'p;s/./=/g;p;g'
|
||||
# Put stdin (possibly several lines separated by ". ") in a box.
|
||||
# Prefix each line by 'col' and terminate each with 'std', for coloring.
|
||||
# Multi line coloring is problematic with "less -R", so we really need
|
||||
# to color each line individually.
|
||||
am__text_box = $(AWK) '{ \
|
||||
n = split($$0, lines, "\\. "); max = 0; \
|
||||
for (i = 1; i <= n; ++i) \
|
||||
if (max < length(lines[i])) \
|
||||
max = length(lines[i]); \
|
||||
for (i = 0; i < max; ++i) \
|
||||
line = line "="; \
|
||||
print col line std; \
|
||||
for (i = 1; i <= n; ++i) \
|
||||
if (lines[i]) \
|
||||
print col lines[i] std; \
|
||||
print col line std; \
|
||||
}'
|
||||
# Solaris 10 'make', and several other traditional 'make' implementations,
|
||||
# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
|
||||
# by disabling -e (using the XSI extension "set +e") if it's set.
|
||||
am__sh_e_setup = case $$- in *e*) set +e;; esac
|
||||
# To be inserted before the command running the test. Creates the
|
||||
# directory for the log if needed. Stores in $dir the directory
|
||||
# containing $f, in $tst the test, in $log the log, and passes
|
||||
# TESTS_ENVIRONMENT. Save and restore TERM around use of
|
||||
# TESTS_ENVIRONMENT, in case that unsets it.
|
||||
am__check_pre = \
|
||||
$(am__sh_e_setup); \
|
||||
$(am__vpath_adj_setup) $(am__vpath_adj) \
|
||||
srcdir=$(srcdir); export srcdir; \
|
||||
rm -f $@-t; \
|
||||
am__trap='rm -f '\''$(abs_builddir)/$@-t'\''; (exit $$st); exit $$st'; \
|
||||
trap "st=129; $$am__trap" 1; trap "st=130; $$am__trap" 2; \
|
||||
trap "st=141; $$am__trap" 13; trap "st=143; $$am__trap" 15; \
|
||||
am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`; \
|
||||
test "x$$am__odir" = x. || $(MKDIR_P) "$$am__odir" || exit $$?; \
|
||||
if test -f "./$$f"; then dir=./; \
|
||||
elif test -f "$$f"; then dir=; \
|
||||
else dir="$(srcdir)/"; fi; \
|
||||
tst=$$dir$$f; log='$@'; __SAVED_TERM=$$TERM; \
|
||||
$(TESTS_ENVIRONMENT)
|
||||
# To be appended to the command running the test. Handle the stdout
|
||||
# and stderr redirection, and catch the exit status.
|
||||
am__check_post = \
|
||||
>$@-t 2>&1; \
|
||||
estatus=$$?; \
|
||||
if test -n '$(DISABLE_HARD_ERRORS)' \
|
||||
&& test $$estatus -eq 99; then \
|
||||
estatus=1; \
|
||||
fi; \
|
||||
TERM=$$__SAVED_TERM; export TERM; \
|
||||
$(am__tty_colors); \
|
||||
xfailed=PASS; \
|
||||
case " $(XFAIL_TESTS) " in \
|
||||
*[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
|
||||
xfailed=XFAIL;; \
|
||||
esac; \
|
||||
case $$estatus.$$xfailed in \
|
||||
0.XFAIL) col=$$red; res=XPASS;; \
|
||||
0.*) col=$$grn; res=PASS ;; \
|
||||
77.*) col=$$blu; res=SKIP ;; \
|
||||
99.*) col=$$red; res=FAIL ;; \
|
||||
*.XFAIL) col=$$lgn; res=XFAIL;; \
|
||||
*.*) col=$$red; res=FAIL ;; \
|
||||
esac; \
|
||||
echo "$${col}$$res$${std}: $$f"; \
|
||||
echo "$$res: $$f (exit: $$estatus)" | \
|
||||
$(am__rst_section) >$@; \
|
||||
cat $@-t >>$@; \
|
||||
rm -f $@-t
|
||||
RECHECK_LOGS = $(TEST_LOGS)
|
||||
AM_RECURSIVE_TARGETS = check recheck check-html recheck-html
|
||||
TEST_SUITE_HTML = $(TEST_SUITE_LOG:.log=.html)
|
||||
TEST_SUITE_LOG = test-suite.log
|
||||
TEST_EXTENSIONS = @EXEEXT@ .test
|
||||
LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
|
||||
am__test_logs1 = $(TESTS:=.log)
|
||||
am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
|
||||
TEST_LOGS = $(am__test_logs2:.test.log=.log)
|
||||
TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
|
||||
$(TEST_LOG_FLAGS)
|
||||
TEST_LOGS_TMP = $(TEST_LOGS:.log=.log-t)
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CHECK_CFLAGS = @CHECK_CFLAGS@
|
||||
CHECK_LIBS = @CHECK_LIBS@
|
||||
CP = @CP@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DOXYGEN = @DOXYGEN@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GLIB_CFLAGS = @GLIB_CFLAGS@
|
||||
GLIB_LIBS = @GLIB_LIBS@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIB_RT = @LIB_RT@
|
||||
LINT_FLAGS = @LINT_FLAGS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKGCONFIG = @PKGCONFIG@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
SOCKETDIR = @SOCKETDIR@
|
||||
SPLINT = @SPLINT@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
noinst_HEADERS = ipc_int.h util_int.h ringbuffer_int.h loop_int.h log_int.h map_int.h
|
||||
|
||||
#
|
||||
# Here are a set of rules to help you update your library version information:
|
||||
# Start with version information of ‘0:0:0’ for each libtool library.
|
||||
# Update the version information only immediately before a public release of your software.
|
||||
# More frequent updates are unnecessary, and only guarantee that the current interface number gets larger faster.
|
||||
# If the library source code has changed at all since the last update, then increment revision (‘c:r:a’ becomes ‘c:r+1:a’).
|
||||
# If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0.
|
||||
# If any interfaces have been added since the last public release, then increment age.
|
||||
# If any interfaces have been removed since the last public release, then set age to 0.
|
||||
#
|
||||
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
lib_LTLIBRARIES = libqb.la
|
||||
libqb_la_LDFLAGS = -version-info 11:1:11
|
||||
source_to_lint = util.c hdb.c ringbuffer.c ringbuffer_helper.c array.c \
|
||||
loop.c loop_poll.c loop_job.c loop_timerlist.c \
|
||||
ipcc.c ipcs.c ipc_shm.c ipc_us.c \
|
||||
log.c log_thread.c log_blackbox.c log_file.c \
|
||||
log_syslog.c log_dcs.c log_format.c \
|
||||
map.c skiplist.c hashtable.c trie.c
|
||||
|
||||
libqb_la_SOURCES = $(source_to_lint) unix.c $(am__append_1) \
|
||||
$(am__append_2)
|
||||
libqb_la_LIBADD = @LTLIBOBJS@
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libqb.pc
|
||||
@HAVE_SPLINT_TRUE@check_SCRIPTS = run_splint.sh
|
||||
@HAVE_SPLINT_TRUE@TESTS = $(check_SCRIPTS)
|
||||
@HAVE_SPLINT_TRUE@ALL_LINT_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
@HAVE_SPLINT_TRUE@ $(libqb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CPPFLAGS) \
|
||||
@HAVE_SPLINT_TRUE@ $(LINT_FLAGS)
|
||||
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .html .lo .log .o .obj .test .test$(EXEEXT)
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu lib/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
libqb.pc: $(top_builddir)/config.status $(srcdir)/libqb.pc.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
list2=; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
list2="$$list2 $$p"; \
|
||||
else :; fi; \
|
||||
done; \
|
||||
test -z "$$list2" || { \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
|
||||
}
|
||||
|
||||
uninstall-libLTLIBRARIES:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
$(am__strip_dir) \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
|
||||
done
|
||||
|
||||
clean-libLTLIBRARIES:
|
||||
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
|
||||
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
|
||||
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||
test "$$dir" != "$$p" || dir=.; \
|
||||
echo "rm -f \"$${dir}/so_locations\""; \
|
||||
rm -f "$${dir}/so_locations"; \
|
||||
done
|
||||
libqb.la: $(libqb_la_OBJECTS) $(libqb_la_DEPENDENCIES) $(EXTRA_libqb_la_DEPENDENCIES)
|
||||
$(AM_V_CCLD)$(libqb_la_LINK) -rpath $(libdir) $(libqb_la_OBJECTS) $(libqb_la_LIBADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strchrnul.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strlcat.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strlcpy.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/array.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hashtable.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipc_posix_mq.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipc_shm.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipc_sysv_mq.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipc_us.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipcc.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipcs.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log_blackbox.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log_dcs.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log_file.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log_format.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log_syslog.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log_thread.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop_job.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop_poll.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop_timerlist.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/map.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ringbuffer.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ringbuffer_helper.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/skiplist.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trie.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unix.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Plo@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
install-pkgconfigDATA: $(pkgconfig_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)"
|
||||
@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
|
||||
done
|
||||
|
||||
uninstall-pkgconfigDATA:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
|
||||
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
|
||||
dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
$(TEST_SUITE_LOG): $(TEST_LOGS)
|
||||
@$(am__sh_e_setup); \
|
||||
list='$(TEST_LOGS)'; \
|
||||
results=`for f in $$list; do \
|
||||
test -r $$f && read line < $$f && echo "$$line" \
|
||||
|| echo FAIL; \
|
||||
done`; \
|
||||
all=`echo "$$results" | sed '/^$$/d' | wc -l | sed -e 's/^[ ]*//'`; \
|
||||
fail=`echo "$$results" | grep -c '^FAIL'`; \
|
||||
pass=`echo "$$results" | grep -c '^PASS'`; \
|
||||
skip=`echo "$$results" | grep -c '^SKIP'`; \
|
||||
xfail=`echo "$$results" | grep -c '^XFAIL'`; \
|
||||
xpass=`echo "$$results" | grep -c '^XPASS'`; \
|
||||
failures=`expr $$fail + $$xpass`; \
|
||||
all=`expr $$all - $$skip`; \
|
||||
if test "$$all" -eq 1; then tests=test; All=; \
|
||||
else tests=tests; All="All "; fi; \
|
||||
case fail=$$fail:xpass=$$xpass:xfail=$$xfail in \
|
||||
fail=0:xpass=0:xfail=0) \
|
||||
msg="$$All$$all $$tests passed. "; \
|
||||
exit=true;; \
|
||||
fail=0:xpass=0:xfail=*) \
|
||||
msg="$$All$$all $$tests behaved as expected"; \
|
||||
if test "$$xfail" -eq 1; then xfailures=failure; \
|
||||
else xfailures=failures; fi; \
|
||||
msg="$$msg ($$xfail expected $$xfailures). "; \
|
||||
exit=true;; \
|
||||
fail=*:xpass=0:xfail=*) \
|
||||
msg="$$fail of $$all $$tests failed. "; \
|
||||
exit=false;; \
|
||||
fail=*:xpass=*:xfail=*) \
|
||||
msg="$$failures of $$all $$tests did not behave as expected"; \
|
||||
if test "$$xpass" -eq 1; then xpasses=pass; \
|
||||
else xpasses=passes; fi; \
|
||||
msg="$$msg ($$xpass unexpected $$xpasses). "; \
|
||||
exit=false;; \
|
||||
*) \
|
||||
echo >&2 "incorrect case"; exit 4;; \
|
||||
esac; \
|
||||
if test "$$skip" -ne 0; then \
|
||||
if test "$$skip" -eq 1; then \
|
||||
msg="$$msg($$skip test was not run). "; \
|
||||
else \
|
||||
msg="$$msg($$skip tests were not run). "; \
|
||||
fi; \
|
||||
fi; \
|
||||
{ \
|
||||
echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
|
||||
$(am__rst_title); \
|
||||
echo "$$msg"; \
|
||||
echo; \
|
||||
echo ".. contents:: :depth: 2"; \
|
||||
echo; \
|
||||
for f in $$list; do \
|
||||
test -r $$f && read line < $$f || line=; \
|
||||
case $$line in \
|
||||
PASS:*|XFAIL:*);; \
|
||||
*) echo; cat $$f;; \
|
||||
esac; \
|
||||
done; \
|
||||
} >$(TEST_SUITE_LOG).tmp; \
|
||||
mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
|
||||
if test "$$failures" -ne 0; then \
|
||||
msg="$${msg}See $(subdir)/$(TEST_SUITE_LOG). "; \
|
||||
if test -n "$(PACKAGE_BUGREPORT)"; then \
|
||||
msg="$${msg}Please report to $(PACKAGE_BUGREPORT). "; \
|
||||
fi; \
|
||||
fi; \
|
||||
test x"$$VERBOSE" = x || $$exit || cat $(TEST_SUITE_LOG); \
|
||||
$(am__tty_colors); \
|
||||
if $$exit; then \
|
||||
col="$$grn"; \
|
||||
else \
|
||||
col="$$red"; \
|
||||
fi; \
|
||||
echo "$$msg" | $(am__text_box) "col=$$col" "std=$$std"; \
|
||||
$$exit || exit 1
|
||||
|
||||
check-TESTS recheck:
|
||||
@if test $@ != recheck; then \
|
||||
list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list; \
|
||||
fi
|
||||
@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
|
||||
@list='' list2='$(TEST_LOGS)'; for f in $$list2; do \
|
||||
test .log = $$f && continue; \
|
||||
if test $@ = recheck; then \
|
||||
test -f $$f || continue; \
|
||||
if test -r $$f && read line < $$f; then \
|
||||
case $$line in FAIL*|XPASS*) : ;; *) continue;; esac; \
|
||||
fi; \
|
||||
fi; \
|
||||
if test -z "$$list"; then list=$$f; else list="$$list $$f"; fi; \
|
||||
done; \
|
||||
if test $@ = recheck && test -n "$$list"; then \
|
||||
echo "am--clean: ; rm -f $$list" \
|
||||
| $(MAKE) $(AM_MAKEFLAGS) -f - am--clean || exit 1; \
|
||||
fi; \
|
||||
$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$list"
|
||||
recheck: $(check_SCRIPTS)
|
||||
|
||||
am--mostlyclean-test-html:
|
||||
list='$(TEST_LOGS:.log=.html)'; test -z "$$list" || rm -f $$list
|
||||
rm -f $(TEST_SUITE_HTML)
|
||||
|
||||
.log.html:
|
||||
@list='$(RST2HTML) $$RST2HTML rst2html rst2html.py'; \
|
||||
for r2h in $$list; do \
|
||||
if ($$r2h --version) >/dev/null 2>&1; then \
|
||||
R2H=$$r2h; \
|
||||
fi; \
|
||||
done; \
|
||||
if test -z "$$R2H"; then \
|
||||
echo >&2 "cannot find rst2html, cannot create $@"; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
$$R2H $< >$@.tmp
|
||||
@mv $@.tmp $@
|
||||
|
||||
# Be sure to run check first, and then to convert the result.
|
||||
# Beware of concurrent executions. Run "check" not "check-TESTS", as
|
||||
# check-SCRIPTS and other dependencies are rebuilt by the former only.
|
||||
# And expect check to fail.
|
||||
check-html recheck-html:
|
||||
@target=`echo $@ | sed 's/-html$$//'`; \
|
||||
rv=0; $(MAKE) $(AM_MAKEFLAGS) $$target || rv=$$?; \
|
||||
$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_HTML) TEST_LOGS= || exit 4; \
|
||||
exit $$rv
|
||||
run_splint.sh.log: run_splint.sh
|
||||
@p='run_splint.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
.test.log:
|
||||
@p='$<'; $(am__check_pre) $(TEST_LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
@am__EXEEXT_TRUE@.test$(EXEEXT).log:
|
||||
@am__EXEEXT_TRUE@ @p='$<'; $(am__check_pre) $(TEST_LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
$(MAKE) $(AM_MAKEFLAGS) $(check_SCRIPTS)
|
||||
$(MAKE) $(AM_MAKEFLAGS) check-TESTS
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
|
||||
-test -z "$(TEST_LOGS_TMP)" || rm -f $(TEST_LOGS_TMP)
|
||||
-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
|
||||
|
||||
@HAVE_SPLINT_FALSE@clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf $(DEPDIR) ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-pkgconfigDATA
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am: install-libLTLIBRARIES
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf $(DEPDIR) ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: am--mostlyclean-test-html mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-libLTLIBRARIES uninstall-pkgconfigDATA
|
||||
|
||||
.MAKE: check-am check-html install-am install-strip recheck-html
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am am--mostlyclean-test-html check \
|
||||
check-TESTS check-am check-html clean clean-generic \
|
||||
clean-libLTLIBRARIES clean-libtool ctags distclean \
|
||||
distclean-compile distclean-generic distclean-libtool \
|
||||
distclean-tags distdir dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am \
|
||||
install-libLTLIBRARIES install-man install-pdf install-pdf-am \
|
||||
install-pkgconfigDATA install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
recheck recheck-html tags uninstall uninstall-am \
|
||||
uninstall-libLTLIBRARIES uninstall-pkgconfigDATA
|
||||
|
||||
|
||||
@HAVE_SPLINT_TRUE@run_splint.sh: $(top_srcdir)/configure.ac
|
||||
@HAVE_SPLINT_TRUE@ echo "$(SPLINT) $(ALL_LINT_FLAGS) $(addprefix $(top_srcdir)/lib/, $(source_to_lint))" > $@
|
||||
@HAVE_SPLINT_TRUE@ $(AM_V_GEN)chmod +x $@
|
||||
|
||||
@HAVE_SPLINT_TRUE@dist-clean-local:
|
||||
@HAVE_SPLINT_TRUE@ $(AM_V_GEN)rm -f run_splint.sh
|
||||
|
||||
@HAVE_SPLINT_TRUE@clean-generic:
|
||||
@HAVE_SPLINT_TRUE@ $(AM_V_GEN)rm -f run_splint.sh
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
212
lib/array.c
Normal file
212
lib/array.c
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include <qb/qbarray.h>
|
||||
#include <qb/qbutil.h>
|
||||
|
||||
#define MAX_ELEMENTS_PER_BIN 16
|
||||
#define MAX_BINS 4096
|
||||
|
||||
#define BIN_NUM_GET(_idx_) (_idx_ >> 4)
|
||||
#define ELEM_NUM_GET(_idx_) (_idx_ & 0x0F)
|
||||
|
||||
struct qb_array {
|
||||
void **bin;
|
||||
size_t max_elements;
|
||||
size_t element_size;
|
||||
size_t num_bins;
|
||||
size_t autogrow_elements;
|
||||
qb_thread_lock_t *grow_lock;
|
||||
};
|
||||
|
||||
qb_array_t *
|
||||
qb_array_create(size_t max_elements, size_t element_size)
|
||||
{
|
||||
return qb_array_create_2(max_elements, element_size, 0);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_grow_bin_array(struct qb_array * a, int32_t new_bin_size)
|
||||
{
|
||||
int32_t b;
|
||||
|
||||
a->bin = realloc(a->bin, sizeof(void*) * new_bin_size);
|
||||
if (a->bin == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (b = a->num_bins; b < new_bin_size; b++) {
|
||||
a->bin[b] = NULL;
|
||||
}
|
||||
a->num_bins = new_bin_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
qb_array_t *
|
||||
qb_array_create_2(size_t max_elements, size_t element_size,
|
||||
size_t autogrow_elements)
|
||||
{
|
||||
struct qb_array *a = NULL;
|
||||
int32_t b;
|
||||
|
||||
if (max_elements > (MAX_ELEMENTS_PER_BIN * MAX_BINS)) {
|
||||
errno = -EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (element_size < 1) {
|
||||
errno = -EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (autogrow_elements > MAX_ELEMENTS_PER_BIN) {
|
||||
errno = -EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
a = calloc(1, sizeof(struct qb_array));
|
||||
if (a == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
a->element_size = element_size;
|
||||
a->max_elements = max_elements;
|
||||
b = QB_MIN((max_elements / MAX_ELEMENTS_PER_BIN) + 1, MAX_BINS);
|
||||
a->autogrow_elements = autogrow_elements;
|
||||
a->bin = NULL;
|
||||
if (_grow_bin_array(a, b) < 0) {
|
||||
free(a);
|
||||
return NULL;
|
||||
}
|
||||
a->grow_lock = qb_thread_lock_create(QB_THREAD_LOCK_SHORT);
|
||||
return a;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_array_index(struct qb_array * a, int32_t idx, void **element_out)
|
||||
{
|
||||
int32_t b;
|
||||
int32_t elem;
|
||||
char *bin;
|
||||
int32_t rc;
|
||||
|
||||
if (a == NULL || element_out == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (idx < 0) {
|
||||
return -ERANGE;
|
||||
}
|
||||
if (idx >= a->max_elements) {
|
||||
if (a->autogrow_elements == 0) {
|
||||
return -ERANGE;
|
||||
} else {
|
||||
rc = qb_array_grow(a, idx + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
b = BIN_NUM_GET(idx);
|
||||
assert(b < MAX_BINS);
|
||||
|
||||
if (b >= a->num_bins || a->bin[b] == NULL) {
|
||||
|
||||
(void)qb_thread_lock(a->grow_lock);
|
||||
|
||||
if (b >= a->num_bins) {
|
||||
rc = _grow_bin_array(a, b + 1);
|
||||
if (rc < 0) {
|
||||
goto unlock_error;
|
||||
}
|
||||
}
|
||||
if (a->bin[b] == NULL) {
|
||||
a->bin[b] = calloc(MAX_ELEMENTS_PER_BIN, a->element_size);
|
||||
if (a->bin[b] == NULL) {
|
||||
goto unlock_error;
|
||||
}
|
||||
}
|
||||
|
||||
(void)qb_thread_unlock(a->grow_lock);
|
||||
}
|
||||
|
||||
elem = ELEM_NUM_GET(idx);
|
||||
assert(elem < MAX_ELEMENTS_PER_BIN);
|
||||
|
||||
bin = a->bin[b];
|
||||
*element_out = (bin + (a->element_size * elem));
|
||||
|
||||
return 0;
|
||||
|
||||
unlock_error:
|
||||
|
||||
(void)qb_thread_unlock(a->grow_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t
|
||||
qb_array_num_bins_get(struct qb_array * a)
|
||||
{
|
||||
if (a == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return a->num_bins;
|
||||
}
|
||||
|
||||
size_t
|
||||
qb_array_elems_per_bin_get(struct qb_array * a)
|
||||
{
|
||||
if (a == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return MAX_ELEMENTS_PER_BIN;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_array_grow(struct qb_array * a, size_t max_elements)
|
||||
{
|
||||
int32_t b;
|
||||
int32_t rc = 0;
|
||||
|
||||
if (a == NULL || max_elements > (MAX_ELEMENTS_PER_BIN * MAX_BINS)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (max_elements <= a->max_elements) {
|
||||
return 0;
|
||||
}
|
||||
a->max_elements = max_elements;
|
||||
b = QB_MIN((max_elements / MAX_ELEMENTS_PER_BIN) + 1, MAX_BINS);
|
||||
if (b > a->num_bins) {
|
||||
(void)qb_thread_lock(a->grow_lock);
|
||||
if (b >= a->num_bins) {
|
||||
rc = _grow_bin_array(a, b + 1);
|
||||
}
|
||||
(void)qb_thread_unlock(a->grow_lock);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
qb_array_free(struct qb_array *a)
|
||||
{
|
||||
int32_t i;
|
||||
for (i = 0; i < a->num_bins; i++) {
|
||||
free(a->bin[i]);
|
||||
}
|
||||
(void)qb_thread_lock_destroy(a->grow_lock);
|
||||
free(a);
|
||||
}
|
||||
479
lib/hashtable.c
Normal file
479
lib/hashtable.c
Normal file
@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Steven Dake <sdake@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include <qb/qbmap.h>
|
||||
#include "util_int.h"
|
||||
#include "map_int.h"
|
||||
#include <qb/qblist.h>
|
||||
|
||||
#define FNV_32_PRIME ((uint32_t)0x01000193)
|
||||
|
||||
struct hash_node {
|
||||
struct qb_list_head list;
|
||||
void *value;
|
||||
const char *key;
|
||||
uint32_t refcount;
|
||||
struct qb_list_head notifier_head;
|
||||
};
|
||||
|
||||
struct hash_bucket {
|
||||
struct qb_list_head list_head;
|
||||
};
|
||||
|
||||
struct hash_table {
|
||||
struct qb_map map;
|
||||
size_t count;
|
||||
uint32_t order;
|
||||
uint32_t hash_buckets_len;
|
||||
struct hash_bucket hash_buckets[0];
|
||||
struct qb_list_head notifier_head;
|
||||
};
|
||||
|
||||
struct hashtable_iter {
|
||||
struct qb_map_iter i;
|
||||
struct hash_node *node;
|
||||
uint32_t bucket;
|
||||
};
|
||||
|
||||
static void hashtable_notify(struct hash_table *t, struct hash_node *n,
|
||||
uint32_t event, const char *key,
|
||||
void *old_value, void *value);
|
||||
|
||||
static uint32_t
|
||||
hash_fnv(const void *value, uint32_t valuelen, uint32_t order)
|
||||
{
|
||||
uint8_t *cd = (uint8_t *) value;
|
||||
uint8_t *ed = (uint8_t *) value + valuelen;
|
||||
uint32_t hash_result = 0x811c9dc5;
|
||||
int32_t res;
|
||||
|
||||
while (cd < ed) {
|
||||
hash_result ^= *cd;
|
||||
hash_result *= FNV_32_PRIME;
|
||||
cd++;
|
||||
}
|
||||
res = ((hash_result >> order) ^ hash_result) & ((1 << order) - 1);
|
||||
return (res);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
qb_hash_string(const void *key, uint32_t order)
|
||||
{
|
||||
char *str = (char *)key;
|
||||
return hash_fnv(key, strlen(str), order);
|
||||
}
|
||||
|
||||
static struct hash_node *
|
||||
hashtable_lookup(struct hash_table *t, const char *key)
|
||||
{
|
||||
uint32_t hash_entry;
|
||||
struct qb_list_head *list;
|
||||
struct hash_node *hash_node;
|
||||
|
||||
hash_entry = qb_hash_string(key, t->order);
|
||||
|
||||
for (list = t->hash_buckets[hash_entry].list_head.next;
|
||||
list != &t->hash_buckets[hash_entry].list_head;
|
||||
list = list->next) {
|
||||
|
||||
hash_node = qb_list_entry(list, struct hash_node, list);
|
||||
if (strcmp(hash_node->key, key) == 0) {
|
||||
return hash_node;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
hashtable_get(struct qb_map *map, const char *key)
|
||||
{
|
||||
struct hash_table *t = (struct hash_table *)map;
|
||||
struct hash_node *n = hashtable_lookup(t, key);
|
||||
if (n) {
|
||||
return n->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
hashtable_node_deref(struct qb_map *map, struct hash_node *hash_node)
|
||||
{
|
||||
struct hash_table *t = (struct hash_table *)map;
|
||||
|
||||
hash_node->refcount--;
|
||||
if (hash_node->refcount > 0) {
|
||||
return;
|
||||
}
|
||||
hashtable_notify(t, hash_node,
|
||||
QB_MAP_NOTIFY_DELETED,
|
||||
hash_node->key, hash_node->value, NULL);
|
||||
qb_list_del(&hash_node->list);
|
||||
free(hash_node);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
hashtable_rm_with_hash(struct qb_map *map, const char *key, uint32_t hash_entry)
|
||||
{
|
||||
struct hash_table *hash_table = (struct hash_table *)map;
|
||||
struct qb_list_head *list;
|
||||
struct hash_node *hash_node;
|
||||
|
||||
for (list = hash_table->hash_buckets[hash_entry].list_head.next;
|
||||
list != &hash_table->hash_buckets[hash_entry].list_head;
|
||||
list = list->next) {
|
||||
|
||||
hash_node = qb_list_entry(list, struct hash_node, list);
|
||||
if (strcmp(hash_node->key, key) == 0) {
|
||||
hashtable_node_deref(map, hash_node);
|
||||
hash_table->count--;
|
||||
return QB_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return QB_FALSE;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
hashtable_rm(struct qb_map *map, const char *key)
|
||||
{
|
||||
struct hash_table *hash_table = (struct hash_table *)map;
|
||||
uint32_t hash_entry;
|
||||
|
||||
hash_entry = qb_hash_string(key, hash_table->order);
|
||||
return hashtable_rm_with_hash(map, key, hash_entry);
|
||||
}
|
||||
|
||||
static void
|
||||
hashtable_put(struct qb_map *map, const char *key, const void *value)
|
||||
{
|
||||
struct hash_table *hash_table = (struct hash_table *)map;
|
||||
uint32_t hash_entry;
|
||||
struct hash_node *hash_node = NULL;
|
||||
struct hash_node *node_try;
|
||||
struct qb_list_head *list;
|
||||
|
||||
hash_entry = qb_hash_string(key, hash_table->order);
|
||||
|
||||
for (list = hash_table->hash_buckets[hash_entry].list_head.next;
|
||||
list != &hash_table->hash_buckets[hash_entry].list_head;
|
||||
list = list->next) {
|
||||
|
||||
node_try = qb_list_entry(list, struct hash_node, list);
|
||||
if (strcmp(node_try->key, key) == 0) {
|
||||
hash_node = node_try;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hash_node == NULL) {
|
||||
hash_node = calloc(1, sizeof(struct hash_node));
|
||||
if (hash_node == NULL) {
|
||||
errno = ENOMEM;
|
||||
return;
|
||||
}
|
||||
|
||||
hash_table->count++;
|
||||
hash_node->refcount = 1;
|
||||
hash_node->key = key;
|
||||
hash_node->value = (void *)value;
|
||||
qb_list_init(&hash_node->list);
|
||||
qb_list_add_tail(&hash_node->list,
|
||||
&hash_table->hash_buckets[hash_entry].
|
||||
list_head);
|
||||
qb_list_init(&hash_node->notifier_head);
|
||||
|
||||
hashtable_notify(hash_table, hash_node,
|
||||
QB_MAP_NOTIFY_INSERTED,
|
||||
hash_node->key, NULL, hash_node->value);
|
||||
} else {
|
||||
char *old_k = (char *)hash_node->key;
|
||||
char *old_v = (void *)hash_node->value;
|
||||
hash_node->key = key;
|
||||
hash_node->value = (void *)value;
|
||||
|
||||
hashtable_notify(hash_table, hash_node,
|
||||
QB_MAP_NOTIFY_REPLACED,
|
||||
old_k, old_v, hash_node->value);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hashtable_notify(struct hash_table *t, struct hash_node *n,
|
||||
uint32_t event, const char *key,
|
||||
void *old_value, void *value)
|
||||
{
|
||||
struct qb_list_head *list;
|
||||
struct qb_map_notifier *tn;
|
||||
|
||||
for (list = n->notifier_head.next;
|
||||
list != &n->notifier_head; list = list->next) {
|
||||
tn = qb_list_entry(list, struct qb_map_notifier, list);
|
||||
|
||||
if (tn->events & event) {
|
||||
tn->callback(event, (char *)key, old_value, value,
|
||||
tn->user_data);
|
||||
}
|
||||
}
|
||||
for (list = t->notifier_head.next;
|
||||
list != &t->notifier_head; list = list->next) {
|
||||
tn = qb_list_entry(list, struct qb_map_notifier, list);
|
||||
|
||||
if (tn->events & event) {
|
||||
tn->callback(event, (char *)key, old_value, value,
|
||||
tn->user_data);
|
||||
}
|
||||
if (((event & QB_MAP_NOTIFY_DELETED) ||
|
||||
(event & QB_MAP_NOTIFY_REPLACED)) &&
|
||||
(tn->events & QB_MAP_NOTIFY_FREE)) {
|
||||
tn->callback(QB_MAP_NOTIFY_FREE, (char *)key,
|
||||
old_value, value, tn->user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
hashtable_notify_add(qb_map_t * m, const char *key,
|
||||
qb_map_notify_fn fn, int32_t events, void *user_data)
|
||||
{
|
||||
struct hash_table *t = (struct hash_table *)m;
|
||||
struct qb_map_notifier *f;
|
||||
struct hash_node *n;
|
||||
struct qb_list_head *head = NULL;
|
||||
struct qb_list_head *list;
|
||||
int add_to_tail = QB_FALSE;
|
||||
|
||||
if (key) {
|
||||
n = hashtable_lookup(t, key);
|
||||
if (n) {
|
||||
head = &n->notifier_head;
|
||||
}
|
||||
} else {
|
||||
head = &t->notifier_head;
|
||||
}
|
||||
if (head == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
if (events & QB_MAP_NOTIFY_FREE) {
|
||||
add_to_tail = QB_TRUE;
|
||||
}
|
||||
|
||||
for (list = head->next; list != head; list = list->next) {
|
||||
f = qb_list_entry(list, struct qb_map_notifier, list);
|
||||
|
||||
if (events & QB_MAP_NOTIFY_FREE &&
|
||||
f->events == events) {
|
||||
/* only one free notifier */
|
||||
return -EEXIST;
|
||||
}
|
||||
if (f->events == events &&
|
||||
f->user_data == user_data &&
|
||||
f->callback == fn) {
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
f = malloc(sizeof(struct qb_map_notifier));
|
||||
if (f == NULL) {
|
||||
return -errno;
|
||||
}
|
||||
f->events = events;
|
||||
f->user_data = user_data;
|
||||
f->callback = fn;
|
||||
qb_list_init(&f->list);
|
||||
|
||||
if (add_to_tail) {
|
||||
qb_list_add_tail(&f->list, head);
|
||||
} else {
|
||||
qb_list_add(&f->list, head);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
hashtable_notify_del(qb_map_t * m, const char *key,
|
||||
qb_map_notify_fn fn, int32_t events,
|
||||
int32_t cmp_userdata, void *user_data)
|
||||
{
|
||||
struct hash_table *t = (struct hash_table *)m;
|
||||
struct qb_map_notifier *f;
|
||||
struct hash_node *n;
|
||||
struct qb_list_head *head = NULL;
|
||||
struct qb_list_head *list;
|
||||
struct qb_list_head *next;
|
||||
int32_t found = QB_FALSE;
|
||||
|
||||
if (key) {
|
||||
n = hashtable_lookup(t, key);
|
||||
if (n) {
|
||||
head = &n->notifier_head;
|
||||
}
|
||||
} else {
|
||||
head = &t->notifier_head;
|
||||
}
|
||||
if (head == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
for (list = head->next; list != head; list = next) {
|
||||
f = qb_list_entry(list, struct qb_map_notifier, list);
|
||||
next = list->next;
|
||||
|
||||
if (f->events == events && f->callback == fn) {
|
||||
if (cmp_userdata && (f->user_data == user_data)) {
|
||||
found = QB_TRUE;
|
||||
qb_list_del(&f->list);
|
||||
free(f);
|
||||
} else if (!cmp_userdata) {
|
||||
found = QB_TRUE;
|
||||
qb_list_del(&f->list);
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return 0;
|
||||
} else {
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t
|
||||
hashtable_count_get(struct qb_map *map)
|
||||
{
|
||||
struct hash_table *hash_table = (struct hash_table *)map;
|
||||
return hash_table->count;
|
||||
}
|
||||
|
||||
static qb_map_iter_t *
|
||||
hashtable_iter_create(struct qb_map *map, const char *prefix)
|
||||
{
|
||||
struct hashtable_iter *i = malloc(sizeof(struct hashtable_iter));
|
||||
if (i == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
i->i.m = map;
|
||||
i->node = NULL;
|
||||
i->bucket = 0;
|
||||
return (qb_map_iter_t *) i;
|
||||
}
|
||||
|
||||
static const char *
|
||||
hashtable_iter_next(qb_map_iter_t * it, void **value)
|
||||
{
|
||||
struct hashtable_iter *hi = (struct hashtable_iter *)it;
|
||||
struct hash_table *hash_table = (struct hash_table *)hi->i.m;
|
||||
struct qb_list_head *ln;
|
||||
struct hash_node *hash_node = NULL;
|
||||
int found = QB_FALSE;
|
||||
int cont = QB_TRUE;
|
||||
int b;
|
||||
|
||||
if (hi->node == NULL) {
|
||||
cont = QB_FALSE;
|
||||
}
|
||||
for (b = hi->bucket; b < hash_table->hash_buckets_len && !found; b++) {
|
||||
if (cont) {
|
||||
ln = hi->node->list.next;
|
||||
cont = QB_FALSE;
|
||||
} else {
|
||||
ln = hash_table->hash_buckets[b].list_head.next;
|
||||
}
|
||||
for (; ln != &hash_table->hash_buckets[b].list_head;
|
||||
ln = ln->next) {
|
||||
hash_node = qb_list_entry(ln, struct hash_node, list);
|
||||
if (hash_node->refcount > 0) {
|
||||
found = QB_TRUE;
|
||||
hash_node->refcount++;
|
||||
hi->bucket = b;
|
||||
*value = hash_node->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hi->node) {
|
||||
hashtable_node_deref(hi->i.m, hi->node);
|
||||
}
|
||||
if (!found) {
|
||||
return NULL;
|
||||
}
|
||||
hi->node = hash_node;
|
||||
return hash_node->key;
|
||||
}
|
||||
|
||||
static void
|
||||
hashtable_iter_free(qb_map_iter_t * i)
|
||||
{
|
||||
free(i);
|
||||
}
|
||||
|
||||
static void
|
||||
hashtable_destroy(struct qb_map *map)
|
||||
{
|
||||
struct hash_table *hash_table = (struct hash_table *)map;
|
||||
|
||||
free(hash_table);
|
||||
}
|
||||
|
||||
qb_map_t *
|
||||
qb_hashtable_create(size_t max_size)
|
||||
{
|
||||
int32_t i;
|
||||
int32_t order;
|
||||
int32_t n = max_size;
|
||||
uint64_t size;
|
||||
struct hash_table *ht;
|
||||
|
||||
for (i = 0; n; i++) {
|
||||
n >>= 1;
|
||||
}
|
||||
order = QB_MAX(i, 3);
|
||||
|
||||
size = sizeof(struct hash_table) +
|
||||
(sizeof(struct hash_bucket) * (1 << order));
|
||||
|
||||
ht = calloc(1, size);
|
||||
if (ht == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ht->map.put = hashtable_put;
|
||||
ht->map.get = hashtable_get;
|
||||
ht->map.rm = hashtable_rm;
|
||||
ht->map.count_get = hashtable_count_get;
|
||||
ht->map.iter_create = hashtable_iter_create;
|
||||
ht->map.iter_next = hashtable_iter_next;
|
||||
ht->map.iter_free = hashtable_iter_free;
|
||||
ht->map.destroy = hashtable_destroy;
|
||||
ht->map.notify_add = hashtable_notify_add;
|
||||
ht->map.notify_del = hashtable_notify_del;
|
||||
ht->count = 0;
|
||||
ht->order = order;
|
||||
qb_list_init(&ht->notifier_head);
|
||||
|
||||
ht->hash_buckets_len = 1 << order;
|
||||
for (i = 0; i < ht->hash_buckets_len; i++) {
|
||||
qb_list_init(&ht->hash_buckets[i].list_head);
|
||||
}
|
||||
return (qb_map_t *) ht;
|
||||
}
|
||||
291
lib/hdb.c
Normal file
291
lib/hdb.c
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Steven Dake <sdake@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include <qb/qbhdb.h>
|
||||
#include <qb/qbatomic.h>
|
||||
|
||||
enum QB_HDB_HANDLE_STATE {
|
||||
QB_HDB_HANDLE_STATE_EMPTY,
|
||||
QB_HDB_HANDLE_STATE_PENDINGREMOVAL,
|
||||
QB_HDB_HANDLE_STATE_ACTIVE
|
||||
};
|
||||
|
||||
static void
|
||||
qb_hdb_create_first_run(struct qb_hdb *hdb)
|
||||
{
|
||||
if (hdb->first_run == 1) {
|
||||
hdb->first_run = 0;
|
||||
qb_atomic_init();
|
||||
hdb->handles = qb_array_create(32, sizeof(struct qb_hdb_handle));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qb_hdb_create(struct qb_hdb *hdb)
|
||||
{
|
||||
memset(hdb, 0, sizeof(struct qb_hdb));
|
||||
hdb->first_run = 1;
|
||||
qb_hdb_create_first_run(hdb);
|
||||
}
|
||||
|
||||
void
|
||||
qb_hdb_destroy(struct qb_hdb *hdb)
|
||||
{
|
||||
qb_array_free(hdb->handles);
|
||||
memset(hdb, 0, sizeof(struct qb_hdb));
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_hdb_handle_create(struct qb_hdb *hdb, int32_t instance_size,
|
||||
qb_handle_t * handle_id_out)
|
||||
{
|
||||
int32_t handle;
|
||||
int32_t res = 0;
|
||||
uint32_t check;
|
||||
int32_t found = 0;
|
||||
void *instance;
|
||||
int32_t i;
|
||||
struct qb_hdb_handle *entry = NULL;
|
||||
int32_t handle_count;
|
||||
|
||||
qb_hdb_create_first_run(hdb);
|
||||
|
||||
handle_count = qb_atomic_int_get(&hdb->handle_count);
|
||||
for (handle = 0; handle < handle_count; handle++) {
|
||||
if (qb_array_index(hdb->handles, handle, (void**)&entry) == 0 &&
|
||||
entry->state == QB_HDB_HANDLE_STATE_EMPTY) {
|
||||
found = 1;
|
||||
qb_atomic_int_inc(&entry->ref_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
res = qb_array_grow(hdb->handles, handle_count + 1);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
res = qb_array_index(hdb->handles, handle_count,
|
||||
(void **)&entry);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
qb_atomic_int_inc((int32_t *)&hdb->handle_count);
|
||||
}
|
||||
|
||||
instance = malloc(instance_size);
|
||||
if (instance == 0) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* This code makes sure the random number isn't zero
|
||||
* We use 0 to specify an invalid handle out of the 1^64 address space
|
||||
* If we get 0 200 times in a row, the RNG may be broken
|
||||
*/
|
||||
for (i = 0; i < 200; i++) {
|
||||
check = random();
|
||||
|
||||
if (check != 0 && check != 0xffffffff) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memset(instance, 0, instance_size);
|
||||
|
||||
entry->state = QB_HDB_HANDLE_STATE_ACTIVE;
|
||||
entry->instance = instance;
|
||||
entry->ref_count = 1;
|
||||
entry->check = check;
|
||||
|
||||
*handle_id_out = (((uint64_t) (check)) << 32) | handle;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_hdb_handle_get(struct qb_hdb * hdb, qb_handle_t handle_in, void **instance)
|
||||
{
|
||||
uint32_t check = ((uint32_t) (((uint64_t) handle_in) >> 32));
|
||||
uint32_t handle = handle_in & 0xffffffff;
|
||||
struct qb_hdb_handle *entry;
|
||||
int32_t handle_count;
|
||||
|
||||
qb_hdb_create_first_run(hdb);
|
||||
|
||||
*instance = NULL;
|
||||
handle_count = qb_atomic_int_get(&hdb->handle_count);
|
||||
if (handle >= handle_count) {
|
||||
return (-EBADF);
|
||||
}
|
||||
|
||||
if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
|
||||
entry->state != QB_HDB_HANDLE_STATE_ACTIVE) {
|
||||
return (-EBADF);
|
||||
}
|
||||
|
||||
if (check != 0xffffffff && check != entry->check) {
|
||||
return (-EBADF);
|
||||
}
|
||||
qb_atomic_int_inc(&entry->ref_count);
|
||||
|
||||
*instance = entry->instance;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_hdb_handle_get_always(struct qb_hdb * hdb, qb_handle_t handle_in,
|
||||
void **instance)
|
||||
{
|
||||
return qb_hdb_handle_get(hdb, handle_in, instance);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_hdb_handle_put(struct qb_hdb * hdb, qb_handle_t handle_in)
|
||||
{
|
||||
uint32_t check = ((uint32_t) (((uint64_t) handle_in) >> 32));
|
||||
uint32_t handle = handle_in & 0xffffffff;
|
||||
struct qb_hdb_handle *entry;
|
||||
int32_t handle_count;
|
||||
|
||||
qb_hdb_create_first_run(hdb);
|
||||
|
||||
handle_count = qb_atomic_int_get(&hdb->handle_count);
|
||||
if (handle >= handle_count) {
|
||||
return (-EBADF);
|
||||
}
|
||||
|
||||
if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
|
||||
(check != 0xffffffff && check != entry->check)) {
|
||||
return (-EBADF);
|
||||
}
|
||||
|
||||
if (qb_atomic_int_dec_and_test(&entry->ref_count)) {
|
||||
if (hdb->destructor) {
|
||||
hdb->destructor(entry->instance);
|
||||
}
|
||||
free(entry->instance);
|
||||
memset(entry, 0, sizeof(struct qb_hdb_handle));
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_hdb_handle_destroy(struct qb_hdb * hdb, qb_handle_t handle_in)
|
||||
{
|
||||
uint32_t check = ((uint32_t) (((uint64_t) handle_in) >> 32));
|
||||
uint32_t handle = handle_in & 0xffffffff;
|
||||
int32_t res;
|
||||
struct qb_hdb_handle *entry;
|
||||
int32_t handle_count;
|
||||
|
||||
qb_hdb_create_first_run(hdb);
|
||||
|
||||
handle_count = qb_atomic_int_get(&hdb->handle_count);
|
||||
if (handle >= handle_count) {
|
||||
return (-EBADF);
|
||||
}
|
||||
|
||||
if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
|
||||
(check != 0xffffffff && check != entry->check)) {
|
||||
return (-EBADF);
|
||||
}
|
||||
|
||||
entry->state = QB_HDB_HANDLE_STATE_PENDINGREMOVAL;
|
||||
res = qb_hdb_handle_put(hdb, handle_in);
|
||||
return (res);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_hdb_handle_refcount_get(struct qb_hdb * hdb, qb_handle_t handle_in)
|
||||
{
|
||||
uint32_t check = ((uint32_t) (((uint64_t) handle_in) >> 32));
|
||||
uint32_t handle = handle_in & 0xffffffff;
|
||||
struct qb_hdb_handle *entry;
|
||||
int32_t handle_count;
|
||||
int32_t refcount = 0;
|
||||
|
||||
qb_hdb_create_first_run(hdb);
|
||||
|
||||
handle_count = qb_atomic_int_get(&hdb->handle_count);
|
||||
if (handle >= handle_count) {
|
||||
return (-EBADF);
|
||||
}
|
||||
|
||||
if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
|
||||
(check != 0xffffffff && check != entry->check)) {
|
||||
return (-EBADF);
|
||||
}
|
||||
|
||||
refcount = qb_atomic_int_get(&entry->ref_count);
|
||||
|
||||
return (refcount);
|
||||
}
|
||||
|
||||
void
|
||||
qb_hdb_iterator_reset(struct qb_hdb *hdb)
|
||||
{
|
||||
hdb->iterator = 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_hdb_iterator_next(struct qb_hdb *hdb, void **instance, qb_handle_t * handle)
|
||||
{
|
||||
int32_t res = -1;
|
||||
uint64_t checker;
|
||||
struct qb_hdb_handle *entry;
|
||||
int32_t handle_count;
|
||||
|
||||
handle_count = qb_atomic_int_get(&hdb->handle_count);
|
||||
while (hdb->iterator < handle_count) {
|
||||
res = qb_array_index(hdb->handles,
|
||||
hdb->iterator,
|
||||
(void **)&entry);
|
||||
if (res != 0) {
|
||||
break;
|
||||
}
|
||||
checker = (uint64_t) (entry->check);
|
||||
*handle = (checker << 32) | hdb->iterator;
|
||||
res = qb_hdb_handle_get(hdb, *handle, instance);
|
||||
|
||||
hdb->iterator += 1;
|
||||
if (res == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
qb_hdb_base_convert(qb_handle_t handle)
|
||||
{
|
||||
return (handle & 0xffffffff);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
qb_hdb_nocheck_convert(uint32_t handle)
|
||||
{
|
||||
uint64_t retvalue = 0xffffffffULL << 32 | handle;
|
||||
|
||||
return (retvalue);
|
||||
}
|
||||
211
lib/ipc_int.h
Normal file
211
lib/ipc_int.h
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Red Hat, Inc.
|
||||
*
|
||||
* Author: Steven Dake <sdake@redhat.com>
|
||||
* Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QB_IPC_INT_H_DEFINED
|
||||
#define QB_IPC_INT_H_DEFINED
|
||||
|
||||
#include "os_base.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#ifdef HAVE_MQUEUE_H
|
||||
#include <mqueue.h>
|
||||
#endif /* HAVE_MQUEUE_H */
|
||||
#include <qb/qblist.h>
|
||||
#include <qb/qbloop.h>
|
||||
#include <qb/qbipcc.h>
|
||||
#include <qb/qbipcs.h>
|
||||
#include <qb/qbipc_common.h>
|
||||
#include <qb/qbrb.h>
|
||||
|
||||
#ifdef HAVE_POSIX_SHARED_SEMAPHORE
|
||||
#include <semaphore.h>
|
||||
#endif /* HAVE_POSIX_SHARED_SEMAPHORE */
|
||||
|
||||
#define QB_IPC_MAX_WAIT_MS 2000
|
||||
|
||||
/*
|
||||
Client Server
|
||||
SEND CONN REQ ->
|
||||
ACCEPT & CREATE queues
|
||||
or DENY
|
||||
<- SEND ACCEPT(with details)/DENY
|
||||
*/
|
||||
|
||||
struct qb_ipc_connection_request {
|
||||
struct qb_ipc_request_header hdr __attribute__ ((aligned(8)));
|
||||
uint32_t max_msg_size __attribute__ ((aligned(8)));
|
||||
} __attribute__ ((aligned(8)));
|
||||
|
||||
struct qb_ipc_event_connection_request {
|
||||
struct qb_ipc_request_header hdr __attribute__ ((aligned(8)));
|
||||
intptr_t connection __attribute__ ((aligned(8)));
|
||||
} __attribute__ ((aligned(8)));
|
||||
|
||||
struct qb_ipc_connection_response {
|
||||
struct qb_ipc_response_header hdr __attribute__ ((aligned(8)));
|
||||
int32_t connection_type __attribute__ ((aligned(8)));
|
||||
uint32_t max_msg_size __attribute__ ((aligned(8)));
|
||||
intptr_t connection __attribute__ ((aligned(8)));
|
||||
char request[PATH_MAX] __attribute__ ((aligned(8)));
|
||||
char response[PATH_MAX] __attribute__ ((aligned(8)));
|
||||
char event[PATH_MAX] __attribute__ ((aligned(8)));
|
||||
} __attribute__ ((aligned(8)));
|
||||
|
||||
struct qb_ipcc_connection;
|
||||
|
||||
struct qb_ipc_one_way {
|
||||
size_t max_msg_size;
|
||||
enum qb_ipc_type type;
|
||||
union {
|
||||
struct {
|
||||
int32_t sock;
|
||||
void* shared_data;
|
||||
char shared_file_name[NAME_MAX];
|
||||
} us;
|
||||
#ifdef HAVE_MQUEUE_H
|
||||
struct {
|
||||
mqd_t q;
|
||||
char name[NAME_MAX];
|
||||
} pmq;
|
||||
#endif
|
||||
struct {
|
||||
int32_t q;
|
||||
int32_t key;
|
||||
} smq;
|
||||
struct {
|
||||
qb_ringbuffer_t *rb;
|
||||
} shm;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct qb_ipcc_funcs {
|
||||
ssize_t (*recv)(struct qb_ipc_one_way *one_way, void *buf, size_t buf_size, int32_t timeout);
|
||||
ssize_t (*send)(struct qb_ipc_one_way *one_way, const void *data, size_t size);
|
||||
ssize_t (*sendv)(struct qb_ipc_one_way *one_way, const struct iovec *iov, size_t iov_len);
|
||||
void (*disconnect)(struct qb_ipcc_connection* c);
|
||||
int32_t (*fc_get)(struct qb_ipc_one_way *one_way);
|
||||
};
|
||||
|
||||
struct qb_ipcc_connection {
|
||||
char name[NAME_MAX];
|
||||
int32_t needs_sock_for_poll;
|
||||
struct qb_ipc_one_way setup;
|
||||
struct qb_ipc_one_way request;
|
||||
struct qb_ipc_one_way response;
|
||||
struct qb_ipc_one_way event;
|
||||
struct qb_ipcc_funcs funcs;
|
||||
struct qb_ipc_request_header *receive_buf;
|
||||
uint32_t fc_enable_max;
|
||||
int32_t is_connected;
|
||||
void * context;
|
||||
};
|
||||
|
||||
int32_t qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
|
||||
struct qb_ipc_connection_response *r);
|
||||
ssize_t qb_ipc_us_send(struct qb_ipc_one_way *one_way, const void *msg, size_t len);
|
||||
ssize_t qb_ipc_us_recv(struct qb_ipc_one_way *one_way, void *msg, size_t len, int32_t timeout);
|
||||
int32_t qb_ipc_us_recv_ready(struct qb_ipc_one_way *one_way, int32_t ms_timeout);
|
||||
|
||||
void qb_ipcc_us_sock_close(int32_t sock);
|
||||
|
||||
int32_t qb_ipcc_pmq_connect(struct qb_ipcc_connection *c, struct qb_ipc_connection_response * response);
|
||||
int32_t qb_ipcc_us_connect(struct qb_ipcc_connection *c, struct qb_ipc_connection_response * response);
|
||||
int32_t qb_ipcc_smq_connect(struct qb_ipcc_connection *c, struct qb_ipc_connection_response * response);
|
||||
int32_t qb_ipcc_shm_connect(struct qb_ipcc_connection *c, struct qb_ipc_connection_response * response);
|
||||
|
||||
struct qb_ipcs_service;
|
||||
struct qb_ipcs_connection;
|
||||
|
||||
struct qb_ipcs_funcs {
|
||||
int32_t (*connect)(struct qb_ipcs_service *s, struct qb_ipcs_connection *c,
|
||||
struct qb_ipc_connection_response *r);
|
||||
void (*disconnect)(struct qb_ipcs_connection *c);
|
||||
ssize_t (*recv)(struct qb_ipc_one_way *one_way, void *buf, size_t buf_size, int32_t timeout);
|
||||
ssize_t (*peek)(struct qb_ipc_one_way *one_way, void **data_out, int32_t timeout);
|
||||
void (*reclaim)(struct qb_ipc_one_way *one_way);
|
||||
ssize_t (*send)(struct qb_ipc_one_way *one_way, const void *data, size_t size);
|
||||
ssize_t (*sendv)(struct qb_ipc_one_way *one_way, const struct iovec* iov, size_t iov_len);
|
||||
void (*fc_set)(struct qb_ipc_one_way *one_way, int32_t fc_enable);
|
||||
ssize_t (*q_len_get)(struct qb_ipc_one_way *one_way);
|
||||
};
|
||||
|
||||
struct qb_ipcs_service {
|
||||
enum qb_ipc_type type;
|
||||
char name[NAME_MAX];
|
||||
int32_t service_id;
|
||||
int32_t ref_count;
|
||||
pid_t pid;
|
||||
int32_t needs_sock_for_poll;
|
||||
int32_t server_sock;
|
||||
|
||||
struct qb_ipcs_service_handlers serv_fns;
|
||||
struct qb_ipcs_poll_handlers poll_fns;
|
||||
struct qb_ipcs_funcs funcs;
|
||||
enum qb_loop_priority poll_priority;
|
||||
|
||||
struct qb_list_head connections;
|
||||
struct qb_list_head list;
|
||||
struct qb_ipcs_stats stats;
|
||||
};
|
||||
|
||||
enum qb_ipcs_connection_state {
|
||||
QB_IPCS_CONNECTION_INACTIVE,
|
||||
QB_IPCS_CONNECTION_ACTIVE,
|
||||
QB_IPCS_CONNECTION_ESTABLISHED,
|
||||
QB_IPCS_CONNECTION_SHUTTING_DOWN,
|
||||
};
|
||||
|
||||
struct qb_ipcs_connection {
|
||||
enum qb_ipcs_connection_state state;
|
||||
int32_t refcount;
|
||||
pid_t pid;
|
||||
uid_t euid;
|
||||
gid_t egid;
|
||||
struct qb_ipc_one_way setup;
|
||||
struct qb_ipc_one_way request;
|
||||
struct qb_ipc_one_way response;
|
||||
struct qb_ipc_one_way event;
|
||||
struct qb_ipcs_service *service;
|
||||
struct qb_list_head list;
|
||||
struct qb_ipc_request_header *receive_buf;
|
||||
void *context;
|
||||
int32_t fc_enabled;
|
||||
int32_t poll_events;
|
||||
int32_t outstanding_notifiers;
|
||||
struct qb_ipcs_connection_stats stats;
|
||||
};
|
||||
|
||||
void qb_ipcs_pmq_init(struct qb_ipcs_service *s);
|
||||
void qb_ipcs_us_init(struct qb_ipcs_service *s);
|
||||
void qb_ipcs_smq_init(struct qb_ipcs_service *s);
|
||||
void qb_ipcs_shm_init(struct qb_ipcs_service *s);
|
||||
|
||||
int32_t qb_ipcs_us_publish(struct qb_ipcs_service *s);
|
||||
int32_t qb_ipcs_us_withdraw(struct qb_ipcs_service *s);
|
||||
|
||||
int32_t qb_ipcs_dispatch_connection_request(int32_t fd, int32_t revents, void *data);
|
||||
int32_t qb_ipcs_dispatch_service_request(int32_t fd, int32_t revents, void *data);
|
||||
struct qb_ipcs_connection* qb_ipcs_connection_alloc(struct qb_ipcs_service *s);
|
||||
|
||||
int32_t qb_ipcs_process_request(struct qb_ipcs_service *s,
|
||||
struct qb_ipc_request_header *hdr);
|
||||
|
||||
#endif /* QB_IPC_INT_H_DEFINED */
|
||||
421
lib/ipc_posix_mq.c
Normal file
421
lib/ipc_posix_mq.c
Normal file
@ -0,0 +1,421 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include <mqueue.h>
|
||||
#include <sys/resource.h>
|
||||
#include "ipc_int.h"
|
||||
#include "util_int.h"
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbutil.h>
|
||||
#include <qb/qbloop.h>
|
||||
|
||||
#define QB_REQUEST_Q_LEN 3
|
||||
#define QB_RESPONSE_Q_LEN 1
|
||||
#define QB_EVENT_Q_LEN 3
|
||||
|
||||
static size_t q_space_used = 0;
|
||||
#ifdef QB_LINUX
|
||||
#define QB_RLIMIT_CHANGE_NEEDED 1
|
||||
#endif /* QB_LINUX */
|
||||
|
||||
/*
|
||||
* utility functions
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
static int32_t
|
||||
posix_mq_increase_limits(size_t max_msg_size, int32_t q_len)
|
||||
{
|
||||
int32_t res = 0;
|
||||
#ifdef QB_RLIMIT_CHANGE_NEEDED
|
||||
struct rlimit rlim;
|
||||
size_t q_space_needed;
|
||||
#endif /* QB_RLIMIT_CHANGE_NEEDED */
|
||||
|
||||
#ifdef QB_RLIMIT_CHANGE_NEEDED
|
||||
if (getrlimit(RLIMIT_MSGQUEUE, &rlim) != 0) {
|
||||
res = -errno;
|
||||
qb_util_log(LOG_ERR, "getrlimit failed");
|
||||
return res;
|
||||
}
|
||||
q_space_needed = q_space_used + (max_msg_size * q_len * 4 / 3);
|
||||
|
||||
qb_util_log(LOG_DEBUG, "rlimit:%d needed:%zu used:%zu",
|
||||
(int)rlim.rlim_cur, q_space_needed, q_space_used);
|
||||
|
||||
if (rlim.rlim_cur < q_space_needed) {
|
||||
rlim.rlim_cur = q_space_needed;
|
||||
}
|
||||
if (rlim.rlim_max < q_space_needed) {
|
||||
rlim.rlim_max = q_space_needed;
|
||||
}
|
||||
if (setrlimit(RLIMIT_MSGQUEUE, &rlim) != 0) {
|
||||
res = -errno;
|
||||
qb_util_log(LOG_ERR, "setrlimit failed");
|
||||
}
|
||||
#endif /* QB_RLIMIT_CHANGE_NEEDED */
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
posix_mq_open(struct qb_ipc_one_way *one_way, const char *name, size_t q_len)
|
||||
{
|
||||
int32_t res = posix_mq_increase_limits(one_way->max_msg_size, q_len);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
one_way->u.pmq.q = mq_open(name, O_RDWR);
|
||||
if (one_way->u.pmq.q == (mqd_t) - 1) {
|
||||
res = -errno;
|
||||
perror("mq_open");
|
||||
return res;
|
||||
}
|
||||
(void)strlcpy(one_way->u.pmq.name, name, NAME_MAX);
|
||||
q_space_used += one_way->max_msg_size * q_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
posix_mq_create(struct qb_ipcs_connection *c,
|
||||
struct qb_ipc_one_way *one_way, const char *name, size_t q_len)
|
||||
{
|
||||
struct mq_attr attr;
|
||||
mqd_t q = 0;
|
||||
int32_t res = 0;
|
||||
mode_t m = 0600;
|
||||
size_t max_msg_size = one_way->max_msg_size;
|
||||
|
||||
res = posix_mq_increase_limits(max_msg_size, q_len);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
try_smaller:
|
||||
if (q != 0) {
|
||||
max_msg_size = max_msg_size / 2;
|
||||
q_len--;
|
||||
}
|
||||
attr.mq_flags = O_NONBLOCK;
|
||||
attr.mq_maxmsg = q_len;
|
||||
attr.mq_msgsize = max_msg_size;
|
||||
|
||||
q = mq_open(name, O_RDWR | O_CREAT | O_EXCL | O_NONBLOCK, m, &attr);
|
||||
if (q == (mqd_t) - 1 && errno == ENOMEM) {
|
||||
if (max_msg_size > 9000 && q_len > 3) {
|
||||
goto try_smaller;
|
||||
}
|
||||
}
|
||||
if (q == (mqd_t) - 1) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "Can't create mq \"%s\"", name);
|
||||
return res;
|
||||
}
|
||||
q_space_used += max_msg_size * q_len;
|
||||
one_way->max_msg_size = max_msg_size;
|
||||
one_way->u.pmq.q = q;
|
||||
(void)strlcpy(one_way->u.pmq.name, name, NAME_MAX);
|
||||
|
||||
res = fchown((int)q, c->euid, c->egid);
|
||||
if (res == -1) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "fchown:%s", name);
|
||||
mq_close(q);
|
||||
mq_unlink(name);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_pmq_send(struct qb_ipc_one_way *one_way,
|
||||
const void *msg_ptr, size_t msg_len)
|
||||
{
|
||||
int32_t res = mq_send(one_way->u.pmq.q, msg_ptr, msg_len, 1);
|
||||
if (res != 0) {
|
||||
return -errno;
|
||||
}
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_pmq_sendv(struct qb_ipc_one_way *one_way,
|
||||
const struct iovec *iov, size_t iov_len)
|
||||
{
|
||||
int32_t total_size = 0;
|
||||
int32_t i;
|
||||
int32_t res = 0;
|
||||
char *data = NULL;
|
||||
char *pt = NULL;
|
||||
|
||||
for (i = 0; i < iov_len; i++) {
|
||||
total_size += iov[i].iov_len;
|
||||
}
|
||||
if (total_size == 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
data = malloc(total_size);
|
||||
if (data == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
pt = data;
|
||||
|
||||
for (i = 0; i < iov_len; i++) {
|
||||
memcpy(pt, iov[i].iov_base, iov[i].iov_len);
|
||||
pt += iov[i].iov_len;
|
||||
}
|
||||
|
||||
res = mq_send(one_way->u.pmq.q, data, total_size, 1);
|
||||
free(data);
|
||||
if (res != 0) {
|
||||
return -errno;
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_pmq_recv(struct qb_ipc_one_way *one_way,
|
||||
void *msg_ptr, size_t msg_len, int32_t ms_timeout)
|
||||
{
|
||||
uint32_t msg_prio;
|
||||
struct timespec ts_timeout;
|
||||
ssize_t res;
|
||||
|
||||
if (ms_timeout >= 0) {
|
||||
qb_util_timespec_from_epoch_get(&ts_timeout);
|
||||
qb_timespec_add_ms(&ts_timeout, ms_timeout);
|
||||
}
|
||||
|
||||
mq_receive_again:
|
||||
if (ms_timeout >= 0) {
|
||||
res = mq_timedreceive(one_way->u.pmq.q,
|
||||
(char *)msg_ptr,
|
||||
one_way->max_msg_size,
|
||||
&msg_prio, &ts_timeout);
|
||||
} else {
|
||||
res = mq_receive(one_way->u.pmq.q,
|
||||
(char *)msg_ptr,
|
||||
one_way->max_msg_size, &msg_prio);
|
||||
}
|
||||
if (res == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
goto mq_receive_again;
|
||||
break;
|
||||
case EAGAIN:
|
||||
res = -ETIMEDOUT;
|
||||
break;
|
||||
case ETIMEDOUT:
|
||||
res = -errno;
|
||||
break;
|
||||
default:
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR,
|
||||
"error waiting for mq_timedreceive");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* client functions
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
qb_ipcc_pmq_disconnect(struct qb_ipcc_connection *c)
|
||||
{
|
||||
struct qb_ipc_request_header hdr;
|
||||
|
||||
qb_util_log(LOG_DEBUG, "%s()", __func__);
|
||||
if (c->needs_sock_for_poll) {
|
||||
return;
|
||||
}
|
||||
|
||||
hdr.id = QB_IPC_MSG_DISCONNECT;
|
||||
hdr.size = sizeof(hdr);
|
||||
mq_send(c->request.u.pmq.q, (const char *)&hdr, hdr.size, 30);
|
||||
|
||||
mq_close(c->event.u.pmq.q);
|
||||
mq_close(c->response.u.pmq.q);
|
||||
mq_close(c->request.u.pmq.q);
|
||||
|
||||
mq_unlink(c->event.u.pmq.name);
|
||||
mq_unlink(c->request.u.pmq.name);
|
||||
mq_unlink(c->response.u.pmq.name);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcc_pmq_connect(struct qb_ipcc_connection *c,
|
||||
struct qb_ipc_connection_response *response)
|
||||
{
|
||||
int32_t res = 0;
|
||||
|
||||
c->funcs.send = qb_ipc_pmq_send;
|
||||
c->funcs.sendv = qb_ipc_pmq_sendv;
|
||||
c->funcs.recv = qb_ipc_pmq_recv;
|
||||
c->funcs.fc_get = NULL;
|
||||
c->funcs.disconnect = qb_ipcc_pmq_disconnect;
|
||||
#if defined(QB_LINUX) || defined(QB_BSD)
|
||||
c->needs_sock_for_poll = QB_FALSE;
|
||||
#else
|
||||
c->needs_sock_for_poll = QB_TRUE;
|
||||
#endif
|
||||
|
||||
if (strlen(c->name) > (NAME_MAX - 20)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = posix_mq_open(&c->request, response->request, QB_REQUEST_Q_LEN);
|
||||
if (res != 0) {
|
||||
perror("mq_open:REQUEST");
|
||||
return res;
|
||||
}
|
||||
res = posix_mq_open(&c->response, response->response,
|
||||
QB_RESPONSE_Q_LEN);
|
||||
if (res != 0) {
|
||||
perror("mq_open:RESPONSE");
|
||||
goto cleanup_request;
|
||||
}
|
||||
res = posix_mq_open(&c->event, response->event, QB_EVENT_Q_LEN);
|
||||
if (res != 0) {
|
||||
perror("mq_open:EVENT");
|
||||
goto cleanup_request_response;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_request_response:
|
||||
mq_close(c->response.u.pmq.q);
|
||||
|
||||
cleanup_request:
|
||||
mq_close(c->request.u.pmq.q);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* service functions
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
qb_ipcs_pmq_disconnect(struct qb_ipcs_connection *c)
|
||||
{
|
||||
struct qb_ipc_response_header msg;
|
||||
|
||||
msg.id = QB_IPC_MSG_DISCONNECT;
|
||||
msg.size = sizeof(msg);
|
||||
msg.error = 0;
|
||||
|
||||
(void)qb_ipc_pmq_send(&c->event, &msg, msg.size);
|
||||
|
||||
mq_close(c->event.u.pmq.q);
|
||||
mq_close(c->response.u.pmq.q);
|
||||
mq_close(c->request.u.pmq.q);
|
||||
|
||||
mq_unlink(c->event.u.pmq.name);
|
||||
mq_unlink(c->request.u.pmq.name);
|
||||
mq_unlink(c->response.u.pmq.name);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
qb_ipcs_pmq_connect(struct qb_ipcs_service *s,
|
||||
struct qb_ipcs_connection *c,
|
||||
struct qb_ipc_connection_response *r)
|
||||
{
|
||||
int32_t res = 0;
|
||||
|
||||
snprintf(r->request, NAME_MAX, "/%s-request-%d", s->name, c->pid);
|
||||
snprintf(r->response, NAME_MAX, "/%s-response-%d", s->name, c->pid);
|
||||
snprintf(r->event, NAME_MAX, "/%s-event-%d", s->name, c->pid);
|
||||
|
||||
res = posix_mq_create(c, &c->request, r->request, QB_REQUEST_Q_LEN);
|
||||
if (res < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
res = posix_mq_create(c, &c->response, r->response, QB_RESPONSE_Q_LEN);
|
||||
if (res < 0) {
|
||||
goto cleanup_request;
|
||||
}
|
||||
|
||||
res = posix_mq_create(c, &c->event, r->event, QB_EVENT_Q_LEN);
|
||||
if (res < 0) {
|
||||
goto cleanup_request_response;
|
||||
}
|
||||
|
||||
if (!s->needs_sock_for_poll) {
|
||||
res =
|
||||
s->poll_fns.dispatch_add(s->poll_priority,
|
||||
(int32_t) c->request.u.pmq.q,
|
||||
POLLIN | POLLPRI | POLLNVAL, c,
|
||||
qb_ipcs_dispatch_service_request);
|
||||
}
|
||||
|
||||
r->hdr.error = 0;
|
||||
return res;
|
||||
|
||||
cleanup_request_response:
|
||||
mq_close(c->response.u.pmq.q);
|
||||
mq_unlink(r->response);
|
||||
cleanup_request:
|
||||
mq_close(c->request.u.pmq.q);
|
||||
mq_unlink(r->request);
|
||||
|
||||
cleanup:
|
||||
r->hdr.error = res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_pmq_q_len_get(struct qb_ipc_one_way *one_way)
|
||||
{
|
||||
struct mq_attr info;
|
||||
int32_t res = mq_getattr(one_way->u.pmq.q, &info);
|
||||
if (res == 0) {
|
||||
return info.mq_curmsgs;
|
||||
}
|
||||
return -errno;
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_pmq_init(struct qb_ipcs_service *s)
|
||||
{
|
||||
s->funcs.connect = qb_ipcs_pmq_connect;
|
||||
s->funcs.disconnect = qb_ipcs_pmq_disconnect;
|
||||
|
||||
s->funcs.recv = qb_ipc_pmq_recv;
|
||||
s->funcs.send = qb_ipc_pmq_send;
|
||||
s->funcs.sendv = qb_ipc_pmq_sendv;
|
||||
s->funcs.peek = NULL;
|
||||
s->funcs.reclaim = NULL;
|
||||
|
||||
s->funcs.fc_set = NULL;
|
||||
s->funcs.q_len_get = qb_ipc_pmq_q_len_get;
|
||||
|
||||
#if defined(QB_LINUX) || defined(QB_BSD)
|
||||
s->needs_sock_for_poll = QB_FALSE;
|
||||
#else
|
||||
s->needs_sock_for_poll = QB_TRUE;
|
||||
#endif
|
||||
}
|
||||
335
lib/ipc_shm.c
Normal file
335
lib/ipc_shm.c
Normal file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include "ipc_int.h"
|
||||
#include "util_int.h"
|
||||
#include "ringbuffer_int.h"
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbatomic.h>
|
||||
#include <qb/qbloop.h>
|
||||
#include <qb/qbrb.h>
|
||||
|
||||
/*
|
||||
* utility functions
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* client functions
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
qb_ipcc_shm_disconnect(struct qb_ipcc_connection *c)
|
||||
{
|
||||
if (c->is_connected) {
|
||||
qb_rb_close(c->request.u.shm.rb);
|
||||
qb_rb_close(c->response.u.shm.rb);
|
||||
qb_rb_close(c->event.u.shm.rb);
|
||||
} else {
|
||||
qb_rb_force_close(c->request.u.shm.rb);
|
||||
qb_rb_force_close(c->response.u.shm.rb);
|
||||
qb_rb_force_close(c->event.u.shm.rb);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_shm_send(struct qb_ipc_one_way *one_way,
|
||||
const void *msg_ptr, size_t msg_len)
|
||||
{
|
||||
return qb_rb_chunk_write(one_way->u.shm.rb, msg_ptr, msg_len);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_shm_sendv(struct qb_ipc_one_way *one_way,
|
||||
const struct iovec *iov, size_t iov_len)
|
||||
{
|
||||
char *dest;
|
||||
int32_t res = 0;
|
||||
int32_t total_size = 0;
|
||||
int32_t i;
|
||||
char *pt = NULL;
|
||||
|
||||
if (one_way->u.shm.rb == NULL) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
for (i = 0; i < iov_len; i++) {
|
||||
total_size += iov[i].iov_len;
|
||||
}
|
||||
dest = qb_rb_chunk_alloc(one_way->u.shm.rb, total_size);
|
||||
if (dest == NULL) {
|
||||
return -errno;
|
||||
}
|
||||
pt = dest;
|
||||
|
||||
for (i = 0; i < iov_len; i++) {
|
||||
memcpy(pt, iov[i].iov_base, iov[i].iov_len);
|
||||
pt += iov[i].iov_len;
|
||||
}
|
||||
res = qb_rb_chunk_commit(one_way->u.shm.rb, total_size);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_shm_recv(struct qb_ipc_one_way *one_way,
|
||||
void *msg_ptr, size_t msg_len, int32_t ms_timeout)
|
||||
{
|
||||
if (one_way->u.shm.rb == NULL) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
return qb_rb_chunk_read(one_way->u.shm.rb,
|
||||
(void *)msg_ptr, msg_len, ms_timeout);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_shm_peek(struct qb_ipc_one_way *one_way, void **data_out,
|
||||
int32_t ms_timeout)
|
||||
{
|
||||
if (one_way->u.shm.rb == NULL) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
return qb_rb_chunk_peek(one_way->u.shm.rb, data_out, ms_timeout);
|
||||
}
|
||||
|
||||
static void
|
||||
qb_ipc_shm_reclaim(struct qb_ipc_one_way *one_way)
|
||||
{
|
||||
if (one_way->u.shm.rb != NULL) {
|
||||
qb_rb_chunk_reclaim(one_way->u.shm.rb);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qb_ipc_shm_fc_set(struct qb_ipc_one_way *one_way, int32_t fc_enable)
|
||||
{
|
||||
int32_t *fc;
|
||||
fc = qb_rb_shared_user_data_get(one_way->u.shm.rb);
|
||||
qb_util_log(LOG_TRACE, "setting fc to %d", fc_enable);
|
||||
qb_atomic_int_set(fc, fc_enable);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
qb_ipc_shm_fc_get(struct qb_ipc_one_way *one_way)
|
||||
{
|
||||
int32_t *fc;
|
||||
int32_t rc = qb_rb_refcount_get(one_way->u.shm.rb);
|
||||
|
||||
if (rc != 2) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
fc = qb_rb_shared_user_data_get(one_way->u.shm.rb);
|
||||
return qb_atomic_int_get(fc);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_shm_q_len_get(struct qb_ipc_one_way *one_way)
|
||||
{
|
||||
if (one_way->u.shm.rb == NULL) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
return qb_rb_chunks_used(one_way->u.shm.rb);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcc_shm_connect(struct qb_ipcc_connection * c,
|
||||
struct qb_ipc_connection_response * response)
|
||||
{
|
||||
int32_t res = 0;
|
||||
|
||||
c->funcs.send = qb_ipc_shm_send;
|
||||
c->funcs.sendv = qb_ipc_shm_sendv;
|
||||
c->funcs.recv = qb_ipc_shm_recv;
|
||||
c->funcs.fc_get = qb_ipc_shm_fc_get;
|
||||
c->funcs.disconnect = qb_ipcc_shm_disconnect;
|
||||
c->needs_sock_for_poll = QB_TRUE;
|
||||
|
||||
if (strlen(c->name) > (NAME_MAX - 20)) {
|
||||
errno = EINVAL;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
c->request.u.shm.rb = qb_rb_open(response->request,
|
||||
c->request.max_msg_size,
|
||||
QB_RB_FLAG_SHARED_PROCESS,
|
||||
sizeof(int32_t));
|
||||
if (c->request.u.shm.rb == NULL) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "qb_rb_open:REQUEST");
|
||||
goto return_error;
|
||||
}
|
||||
c->response.u.shm.rb = qb_rb_open(response->response,
|
||||
c->response.max_msg_size,
|
||||
QB_RB_FLAG_SHARED_PROCESS, 0);
|
||||
|
||||
if (c->response.u.shm.rb == NULL) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "qb_rb_open:RESPONSE");
|
||||
goto cleanup_request;
|
||||
}
|
||||
c->event.u.shm.rb = qb_rb_open(response->event,
|
||||
c->response.max_msg_size,
|
||||
QB_RB_FLAG_SHARED_PROCESS, 0);
|
||||
|
||||
if (c->event.u.shm.rb == NULL) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "qb_rb_open:EVENT");
|
||||
goto cleanup_request_response;
|
||||
}
|
||||
return 0;
|
||||
|
||||
cleanup_request_response:
|
||||
qb_rb_close(c->response.u.shm.rb);
|
||||
|
||||
cleanup_request:
|
||||
qb_rb_close(c->request.u.shm.rb);
|
||||
|
||||
return_error:
|
||||
errno = -res;
|
||||
qb_util_perror(LOG_ERR, "connection failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* service functions
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
qb_ipcs_shm_disconnect(struct qb_ipcs_connection *c)
|
||||
{
|
||||
if (c->response.u.shm.rb) {
|
||||
qb_rb_close(c->response.u.shm.rb);
|
||||
c->response.u.shm.rb = NULL;
|
||||
}
|
||||
if (c->event.u.shm.rb) {
|
||||
qb_rb_close(c->event.u.shm.rb);
|
||||
c->event.u.shm.rb = NULL;
|
||||
}
|
||||
if (c->request.u.shm.rb) {
|
||||
qb_rb_close(c->request.u.shm.rb);
|
||||
c->request.u.shm.rb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
qb_ipcs_shm_connect(struct qb_ipcs_service *s,
|
||||
struct qb_ipcs_connection *c,
|
||||
struct qb_ipc_connection_response *r)
|
||||
{
|
||||
int32_t res;
|
||||
|
||||
qb_util_log(LOG_DEBUG, "connecting to client [%d]", c->pid);
|
||||
|
||||
snprintf(r->request, NAME_MAX, "%s-request-%d-%d", s->name, c->pid,
|
||||
c->setup.u.us.sock);
|
||||
snprintf(r->response, NAME_MAX, "%s-response-%d-%d", s->name, c->pid,
|
||||
c->setup.u.us.sock);
|
||||
snprintf(r->event, NAME_MAX, "%s-event-%d-%d", s->name, c->pid,
|
||||
c->setup.u.us.sock);
|
||||
|
||||
c->request.u.shm.rb = qb_rb_open(r->request,
|
||||
c->request.max_msg_size,
|
||||
QB_RB_FLAG_CREATE |
|
||||
QB_RB_FLAG_SHARED_PROCESS,
|
||||
sizeof(int32_t));
|
||||
if (c->request.u.shm.rb == NULL) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "qb_rb_open:REQUEST");
|
||||
goto cleanup;
|
||||
}
|
||||
res = qb_rb_chown(c->request.u.shm.rb, c->euid, c->egid);
|
||||
if (res != 0) {
|
||||
qb_util_perror(LOG_ERR, "qb_rb_chown:REQUEST");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
c->response.u.shm.rb = qb_rb_open(r->response,
|
||||
c->response.max_msg_size,
|
||||
QB_RB_FLAG_CREATE |
|
||||
QB_RB_FLAG_SHARED_PROCESS, 0);
|
||||
if (c->response.u.shm.rb == NULL) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "qb_rb_open:RESPONSE");
|
||||
goto cleanup_request;
|
||||
}
|
||||
res = qb_rb_chown(c->response.u.shm.rb, c->euid, c->egid);
|
||||
if (res != 0) {
|
||||
qb_util_perror(LOG_ERR, "qb_rb_chown:RESPONSE");
|
||||
goto cleanup_request;
|
||||
}
|
||||
|
||||
c->event.u.shm.rb = qb_rb_open(r->event,
|
||||
c->event.max_msg_size,
|
||||
QB_RB_FLAG_CREATE |
|
||||
QB_RB_FLAG_SHARED_PROCESS, 0);
|
||||
|
||||
if (c->event.u.shm.rb == NULL) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "qb_rb_open:EVENT");
|
||||
goto cleanup_request_response;
|
||||
}
|
||||
res = qb_rb_chown(c->event.u.shm.rb, c->euid, c->egid);
|
||||
if (res != 0) {
|
||||
qb_util_perror(LOG_ERR, "qb_rb_chown:EVENT");
|
||||
goto cleanup_all;
|
||||
}
|
||||
|
||||
r->hdr.error = 0;
|
||||
return 0;
|
||||
|
||||
cleanup_all:
|
||||
qb_rb_close(c->event.u.shm.rb);
|
||||
|
||||
cleanup_request_response:
|
||||
qb_rb_close(c->request.u.shm.rb);
|
||||
|
||||
cleanup_request:
|
||||
qb_rb_close(c->response.u.shm.rb);
|
||||
|
||||
cleanup:
|
||||
r->hdr.error = res;
|
||||
errno = -res;
|
||||
qb_util_perror(LOG_ERR, "shm connection FAILED");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_shm_init(struct qb_ipcs_service *s)
|
||||
{
|
||||
s->funcs.connect = qb_ipcs_shm_connect;
|
||||
s->funcs.disconnect = qb_ipcs_shm_disconnect;
|
||||
|
||||
s->funcs.recv = qb_ipc_shm_recv;
|
||||
s->funcs.peek = qb_ipc_shm_peek;
|
||||
s->funcs.reclaim = qb_ipc_shm_reclaim;
|
||||
s->funcs.send = qb_ipc_shm_send;
|
||||
s->funcs.sendv = qb_ipc_shm_sendv;
|
||||
|
||||
s->funcs.fc_set = qb_ipc_shm_fc_set;
|
||||
s->funcs.q_len_get = qb_ipc_shm_q_len_get;
|
||||
|
||||
s->needs_sock_for_poll = QB_TRUE;
|
||||
}
|
||||
394
lib/ipc_sysv_mq.c
Normal file
394
lib/ipc_sysv_mq.c
Normal file
@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#ifdef HAVE_SYS_IPC_H
|
||||
#include <sys/ipc.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MSG_H
|
||||
#include <sys/msg.h>
|
||||
#endif
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbloop.h>
|
||||
#include "ipc_int.h"
|
||||
#include "util_int.h"
|
||||
|
||||
#ifndef MSGMAX
|
||||
#define MSGMAX 8192
|
||||
#endif
|
||||
|
||||
#define MY_DATA_SIZE 8000
|
||||
struct my_msgbuf {
|
||||
int32_t id __attribute__ ((aligned(8)));
|
||||
char data[MY_DATA_SIZE] __attribute__ ((aligned(8)));
|
||||
} __attribute__ ((aligned(8)));
|
||||
|
||||
/*
|
||||
* utility functions
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
static int32_t
|
||||
sysv_mq_unnamed_create(struct qb_ipcs_connection *c,
|
||||
struct qb_ipc_one_way *queue)
|
||||
{
|
||||
struct msqid_ds info;
|
||||
int32_t res = 0;
|
||||
|
||||
retry_creating_the_q:
|
||||
queue->u.smq.key = random();
|
||||
queue->u.smq.q =
|
||||
msgget(queue->u.smq.key,
|
||||
IPC_CREAT | IPC_EXCL | IPC_NOWAIT | S_IWUSR | S_IRUSR);
|
||||
if (queue->u.smq.q == -1 && errno == EEXIST) {
|
||||
goto retry_creating_the_q;
|
||||
} else if (queue->u.smq.q == -1) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* change the queue size and change the ownership to that of
|
||||
* the client so they can access it.
|
||||
*/
|
||||
res = msgctl(queue->u.smq.q, IPC_STAT, &info);
|
||||
if (res != 0) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "error getting sysv-mq info");
|
||||
return res;
|
||||
}
|
||||
|
||||
if (info.msg_perm.uid != 0) {
|
||||
qb_util_log(LOG_WARNING,
|
||||
"not enough privileges to increase msg_qbytes");
|
||||
return res;
|
||||
}
|
||||
info.msg_qbytes = 2 * queue->max_msg_size;
|
||||
info.msg_perm.uid = c->euid;
|
||||
info.msg_perm.gid = c->egid;
|
||||
|
||||
res = msgctl(queue->u.smq.q, IPC_SET, &info);
|
||||
if (res != 0) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR,
|
||||
"error modifying the SYSV message queue");
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
sysv_split_and_send(int32_t q, const void *msg_ptr,
|
||||
size_t msg_len, int32_t last_chunk)
|
||||
{
|
||||
int32_t res;
|
||||
int32_t sent = 0;
|
||||
#ifdef PACK_MESSAGES
|
||||
char *progress = (char *)msg_ptr;
|
||||
struct my_msgbuf buf;
|
||||
size_t to_send_now; /* to send in this message */
|
||||
size_t to_send_next; /* to send in next message */
|
||||
|
||||
do {
|
||||
to_send_now = QB_MIN(msg_len - sent, MY_DATA_SIZE);
|
||||
to_send_next = msg_len - (sent + to_send_now);
|
||||
/* receiver used the ID to check to see if there
|
||||
* is more to receive for this message.
|
||||
*/
|
||||
if (last_chunk) {
|
||||
buf.id = to_send_next + 1;
|
||||
} else {
|
||||
buf.id = to_send_next + 1 + msg_len;
|
||||
}
|
||||
memcpy(buf.data, progress, to_send_now);
|
||||
res = msgsnd(q, &buf, to_send_now, IPC_NOWAIT);
|
||||
if (res == 0) {
|
||||
sent += to_send_now;
|
||||
progress += to_send_now;
|
||||
} else {
|
||||
goto return_status;
|
||||
}
|
||||
|
||||
} while (sent < msg_len);
|
||||
|
||||
return_status:
|
||||
#else
|
||||
res = msgsnd(q, msg_ptr, msg_len, IPC_NOWAIT);
|
||||
sent = msg_len;
|
||||
#endif
|
||||
if (res == -1) {
|
||||
return -errno;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
/*
|
||||
* client functions
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
static ssize_t
|
||||
qb_ipc_smq_send(struct qb_ipc_one_way *one_way,
|
||||
const void *msg_ptr, size_t msg_len)
|
||||
{
|
||||
return sysv_split_and_send(one_way->u.smq.q, msg_ptr, msg_len, QB_TRUE);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_smq_sendv(struct qb_ipc_one_way *one_way,
|
||||
const struct iovec *iov, size_t iov_len)
|
||||
{
|
||||
int32_t res;
|
||||
int32_t sent = 0;
|
||||
struct my_msgbuf buf;
|
||||
int32_t i;
|
||||
|
||||
for (i = 0; i < iov_len; i++) {
|
||||
if (iov[i].iov_len <= MY_DATA_SIZE) {
|
||||
if (i == iov_len - 1) {
|
||||
buf.id = 1;
|
||||
} else {
|
||||
buf.id = i + iov[i].iov_len;
|
||||
}
|
||||
memcpy(buf.data, iov[i].iov_base, iov[i].iov_len);
|
||||
res = msgsnd(one_way->u.smq.q,
|
||||
&buf, iov[i].iov_len,
|
||||
IPC_NOWAIT);
|
||||
if (res == 0) {
|
||||
res = iov[i].iov_len;
|
||||
} else {
|
||||
res = -errno;
|
||||
}
|
||||
} else {
|
||||
res = sysv_split_and_send(one_way->u.smq.q,
|
||||
iov[i].iov_base,
|
||||
iov[i].iov_len,
|
||||
(i == iov_len - 1));
|
||||
}
|
||||
if (res > 0) {
|
||||
sent += res;
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_smq_recv(struct qb_ipc_one_way *one_way,
|
||||
void *msg_ptr, size_t msg_len, int32_t ms_timeout)
|
||||
{
|
||||
ssize_t res;
|
||||
ssize_t received = 0;
|
||||
#ifdef PACK_MESSAGES
|
||||
char *progress = (char *)msg_ptr;
|
||||
struct my_msgbuf buf;
|
||||
|
||||
do {
|
||||
try_again:
|
||||
res = msgrcv(one_way->u.smq.q, &buf,
|
||||
MY_DATA_SIZE, 0, IPC_NOWAIT);
|
||||
|
||||
if (res == -1 && errno == ENOMSG) {
|
||||
goto try_again;
|
||||
}
|
||||
//printf("res:%zd, ID:%d\n", res, buf.id);
|
||||
if (res == -1) {
|
||||
goto return_status;
|
||||
}
|
||||
memcpy(progress, buf.data, res);
|
||||
received += res;
|
||||
progress += res;
|
||||
} while (buf.id > 1);
|
||||
return_status:
|
||||
#else
|
||||
res = msgrcv(one_way->u.smq.q, msg_ptr, msg_len, 0, IPC_NOWAIT);
|
||||
received = res;
|
||||
#endif
|
||||
if (res == -1 && errno == ENOMSG) {
|
||||
/* just to be consistent with other IPC types.
|
||||
*/
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (res == -1) {
|
||||
perror(__func__);
|
||||
return -errno;
|
||||
}
|
||||
return received;
|
||||
}
|
||||
|
||||
static void
|
||||
qb_ipcc_smq_disconnect(struct qb_ipcc_connection *c)
|
||||
{
|
||||
struct qb_ipc_request_header hdr;
|
||||
|
||||
qb_util_log(LOG_TRACE, "%s()", __func__);
|
||||
|
||||
hdr.id = QB_IPC_MSG_DISCONNECT;
|
||||
hdr.size = sizeof(hdr);
|
||||
(void)sysv_split_and_send(c->request.u.smq.q,
|
||||
(const char *)&hdr, hdr.size, QB_TRUE);
|
||||
|
||||
msgctl(c->event.u.smq.q, IPC_RMID, NULL);
|
||||
msgctl(c->response.u.smq.q, IPC_RMID, NULL);
|
||||
msgctl(c->request.u.smq.q, IPC_RMID, NULL);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcc_smq_connect(struct qb_ipcc_connection *c,
|
||||
struct qb_ipc_connection_response *response)
|
||||
{
|
||||
int32_t res = 0;
|
||||
|
||||
c->funcs.send = qb_ipc_smq_send;
|
||||
c->funcs.sendv = qb_ipc_smq_sendv;
|
||||
c->funcs.recv = qb_ipc_smq_recv;
|
||||
c->funcs.fc_get = NULL;
|
||||
c->funcs.disconnect = qb_ipcc_smq_disconnect;
|
||||
c->needs_sock_for_poll = QB_TRUE;
|
||||
|
||||
if (strlen(c->name) > (NAME_MAX - 20)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&c->request.u.smq.key, response->request, sizeof(uint32_t));
|
||||
c->request.u.smq.q = msgget(c->request.u.smq.key, IPC_NOWAIT);
|
||||
if (c->request.u.smq.q == -1) {
|
||||
res = -errno;
|
||||
perror("msgget:REQUEST");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memcpy(&c->response.u.smq.key, response->response, sizeof(uint32_t));
|
||||
c->response.u.smq.q = msgget(c->response.u.smq.key, IPC_NOWAIT);
|
||||
if (c->response.u.smq.q == -1) {
|
||||
res = -errno;
|
||||
perror("msgget:RESPONSE");
|
||||
goto cleanup_request;
|
||||
}
|
||||
|
||||
memcpy(&c->event.u.smq.key, response->event, sizeof(uint32_t));
|
||||
c->event.u.smq.q = msgget(c->event.u.smq.key, IPC_NOWAIT);
|
||||
if (c->event.u.smq.q == -1) {
|
||||
res = -errno;
|
||||
perror("msgget:EVENT");
|
||||
goto cleanup_request_response;
|
||||
}
|
||||
return 0;
|
||||
|
||||
cleanup_request_response:
|
||||
msgctl(c->response.u.smq.q, IPC_RMID, NULL);
|
||||
cleanup_request:
|
||||
msgctl(c->request.u.smq.q, IPC_RMID, NULL);
|
||||
cleanup:
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* service functions
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
qb_ipcs_smq_disconnect(struct qb_ipcs_connection *c)
|
||||
{
|
||||
struct qb_ipc_response_header msg;
|
||||
|
||||
if (c->setup.u.us.sock != -1) {
|
||||
msg.id = QB_IPC_MSG_DISCONNECT;
|
||||
msg.size = sizeof(msg);
|
||||
msg.error = 0;
|
||||
|
||||
(void)qb_ipc_smq_send(&c->event, &msg, msg.size);
|
||||
} else {
|
||||
msgctl(c->event.u.smq.q, IPC_RMID, NULL);
|
||||
msgctl(c->response.u.smq.q, IPC_RMID, NULL);
|
||||
msgctl(c->request.u.smq.q, IPC_RMID, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
qb_ipcs_smq_connect(struct qb_ipcs_service *s,
|
||||
struct qb_ipcs_connection *c,
|
||||
struct qb_ipc_connection_response *r)
|
||||
{
|
||||
int32_t res = 0;
|
||||
|
||||
res = sysv_mq_unnamed_create(c, &c->request);
|
||||
if (res < 0) {
|
||||
res = -errno;
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(r->request, &c->request.u.smq.key, sizeof(int32_t));
|
||||
|
||||
res = sysv_mq_unnamed_create(c, &c->response);
|
||||
if (res < 0) {
|
||||
res = -errno;
|
||||
goto cleanup_request;
|
||||
}
|
||||
memcpy(r->response, &c->response.u.smq.key, sizeof(int32_t));
|
||||
|
||||
res = sysv_mq_unnamed_create(c, &c->event);
|
||||
if (res < 0) {
|
||||
res = -errno;
|
||||
goto cleanup_request_response;
|
||||
}
|
||||
memcpy(r->event, &c->event.u.smq.key, sizeof(int32_t));
|
||||
|
||||
r->hdr.error = 0;
|
||||
return 0;
|
||||
|
||||
cleanup_request_response:
|
||||
msgctl(c->response.u.smq.q, IPC_RMID, NULL);
|
||||
cleanup_request:
|
||||
msgctl(c->request.u.smq.q, IPC_RMID, NULL);
|
||||
|
||||
cleanup:
|
||||
r->hdr.error = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_smq_q_len_get(struct qb_ipc_one_way *one_way)
|
||||
{
|
||||
struct msqid_ds info;
|
||||
int32_t res = msgctl(one_way->u.smq.q, IPC_STAT, &info);
|
||||
if (res == 0) {
|
||||
return info.msg_qnum;
|
||||
}
|
||||
return -errno;
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_smq_init(struct qb_ipcs_service *s)
|
||||
{
|
||||
s->funcs.connect = qb_ipcs_smq_connect;
|
||||
s->funcs.disconnect = qb_ipcs_smq_disconnect;
|
||||
|
||||
s->funcs.send = qb_ipc_smq_send;
|
||||
s->funcs.sendv = qb_ipc_smq_sendv;
|
||||
s->funcs.recv = qb_ipc_smq_recv;
|
||||
s->funcs.peek = NULL;
|
||||
s->funcs.reclaim = NULL;
|
||||
|
||||
s->funcs.fc_set = NULL;
|
||||
s->funcs.q_len_get = qb_ipc_smq_q_len_get;
|
||||
|
||||
s->needs_sock_for_poll = QB_TRUE;
|
||||
}
|
||||
971
lib/ipc_us.c
Normal file
971
lib/ipc_us.c
Normal file
@ -0,0 +1,971 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#if defined(HAVE_GETPEERUCRED)
|
||||
#include <ucred.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif /* HAVE_SYS_UN_H */
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <qb/qbatomic.h>
|
||||
#include <qb/qbipcs.h>
|
||||
#include <qb/qbloop.h>
|
||||
#include <qb/qbdefs.h>
|
||||
|
||||
#include "util_int.h"
|
||||
#include "ipc_int.h"
|
||||
|
||||
#define SERVER_BACKLOG 5
|
||||
|
||||
#ifndef UNIX_PATH_MAX
|
||||
#define UNIX_PATH_MAX 108
|
||||
#endif /* UNIX_PATH_MAX */
|
||||
|
||||
#if defined(QB_LINUX) || defined(QB_SOLARIS)
|
||||
#define QB_SUN_LEN(a) sizeof(*(a))
|
||||
#else
|
||||
#define QB_SUN_LEN(a) SUN_LEN(a)
|
||||
#endif
|
||||
|
||||
struct ipc_us_control {
|
||||
int32_t sent;
|
||||
int32_t flow_control;
|
||||
};
|
||||
|
||||
struct ipc_auth_ugp {
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
static int32_t qb_ipcs_us_connection_acceptor(int fd, int revent, void *data);
|
||||
static int32_t qb_ipc_us_fc_get(struct qb_ipc_one_way *one_way);
|
||||
|
||||
#ifdef SO_NOSIGPIPE
|
||||
static void
|
||||
socket_nosigpipe(int32_t s)
|
||||
{
|
||||
int32_t on = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(on));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MSG_NOSIGNAL
|
||||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
ssize_t
|
||||
qb_ipc_us_send(struct qb_ipc_one_way *one_way, const void *msg, size_t len)
|
||||
{
|
||||
int32_t result;
|
||||
struct msghdr msg_send;
|
||||
struct iovec iov_send;
|
||||
char *rbuf = (char *)msg;
|
||||
int32_t processed = 0;
|
||||
struct ipc_us_control *ctl = NULL;
|
||||
|
||||
msg_send.msg_iov = &iov_send;
|
||||
msg_send.msg_iovlen = 1;
|
||||
msg_send.msg_name = 0;
|
||||
msg_send.msg_namelen = 0;
|
||||
|
||||
#if !defined(QB_SOLARIS)
|
||||
msg_send.msg_control = 0;
|
||||
msg_send.msg_controllen = 0;
|
||||
msg_send.msg_flags = 0;
|
||||
#else
|
||||
msg_send.msg_accrights = NULL;
|
||||
msg_send.msg_accrightslen = 0;
|
||||
#endif
|
||||
|
||||
retry_send:
|
||||
iov_send.iov_base = &rbuf[processed];
|
||||
iov_send.iov_len = len - processed;
|
||||
|
||||
result = sendmsg(one_way->u.us.sock, &msg_send, MSG_NOSIGNAL);
|
||||
if (result == -1) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
processed += result;
|
||||
if (processed != len) {
|
||||
goto retry_send;
|
||||
}
|
||||
if (one_way->type == QB_IPC_SOCKET) {
|
||||
ctl = (struct ipc_us_control *)one_way->u.us.shared_data;
|
||||
if (ctl) {
|
||||
qb_atomic_int_inc(&ctl->sent);
|
||||
}
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_us_sendv(struct qb_ipc_one_way *one_way, const struct iovec *iov,
|
||||
size_t iov_len)
|
||||
{
|
||||
int32_t result;
|
||||
struct msghdr msg_send;
|
||||
int32_t processed = 0;
|
||||
size_t len = 0;
|
||||
int32_t i;
|
||||
struct ipc_us_control *ctl = NULL;
|
||||
|
||||
for (i = 0; i < iov_len; i++) {
|
||||
len += iov[i].iov_len;
|
||||
}
|
||||
msg_send.msg_iov = (struct iovec *)iov;
|
||||
msg_send.msg_iovlen = iov_len;
|
||||
msg_send.msg_name = 0;
|
||||
msg_send.msg_namelen = 0;
|
||||
|
||||
#if !defined(QB_SOLARIS)
|
||||
msg_send.msg_control = 0;
|
||||
msg_send.msg_controllen = 0;
|
||||
msg_send.msg_flags = 0;
|
||||
#else
|
||||
msg_send.msg_accrights = NULL;
|
||||
msg_send.msg_accrightslen = 0;
|
||||
#endif
|
||||
|
||||
retry_send:
|
||||
result = sendmsg(one_way->u.us.sock, &msg_send, MSG_NOSIGNAL);
|
||||
if (result == -1) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
processed += result;
|
||||
if (processed != len) {
|
||||
goto retry_send;
|
||||
}
|
||||
if (one_way->type == QB_IPC_SOCKET) {
|
||||
ctl = (struct ipc_us_control *)one_way->u.us.shared_data;
|
||||
if (ctl) {
|
||||
qb_atomic_int_inc(&ctl->sent);
|
||||
}
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_us_recv_msghdr(int32_t s, struct msghdr *hdr, char *msg, size_t len)
|
||||
{
|
||||
int32_t result;
|
||||
int32_t processed = 0;
|
||||
|
||||
retry_recv:
|
||||
hdr->msg_iov->iov_base = &msg[processed];
|
||||
hdr->msg_iov->iov_len = len - processed;
|
||||
|
||||
result = recvmsg(s, hdr, MSG_NOSIGNAL | MSG_WAITALL);
|
||||
if (result == -1 && errno == EAGAIN) {
|
||||
goto retry_recv;
|
||||
}
|
||||
if (result == -1) {
|
||||
return -errno;
|
||||
}
|
||||
#if defined(QB_SOLARIS) || defined(QB_BSD) || defined(QB_DARWIN)
|
||||
/* On many OS poll never return POLLHUP or POLLERR.
|
||||
* EOF is detected when recvmsg return 0.
|
||||
*/
|
||||
if (result == 0) {
|
||||
return -errno; //ENOTCONN
|
||||
}
|
||||
#endif
|
||||
|
||||
processed += result;
|
||||
if (processed != len) {
|
||||
goto retry_recv;
|
||||
}
|
||||
assert(processed == len);
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipc_us_recv_ready(struct qb_ipc_one_way * one_way, int32_t ms_timeout)
|
||||
{
|
||||
struct pollfd ufds;
|
||||
int32_t poll_events;
|
||||
|
||||
ufds.fd = one_way->u.us.sock;
|
||||
ufds.events = POLLIN;
|
||||
ufds.revents = 0;
|
||||
|
||||
poll_events = poll(&ufds, 1, ms_timeout);
|
||||
if ((poll_events == -1 && errno == EINTR) || poll_events == 0) {
|
||||
return -EAGAIN;
|
||||
} else if (poll_events == -1) {
|
||||
return -errno;
|
||||
} else if (poll_events == 1 && (ufds.revents & (POLLERR | POLLHUP))) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* recv an entire message - and try hard to get all of it.
|
||||
*/
|
||||
ssize_t
|
||||
qb_ipc_us_recv(struct qb_ipc_one_way * one_way,
|
||||
void *msg, size_t len, int32_t timeout)
|
||||
{
|
||||
int32_t result;
|
||||
int32_t processed = 0;
|
||||
int32_t to_recv = len;
|
||||
char *data = msg;
|
||||
struct ipc_us_control *ctl = NULL;
|
||||
|
||||
retry_recv:
|
||||
result = recv(one_way->u.us.sock, &data[processed], to_recv, MSG_NOSIGNAL | MSG_WAITALL);
|
||||
if (timeout == -1) {
|
||||
if (result == -1 && errno == EAGAIN) {
|
||||
goto retry_recv;
|
||||
}
|
||||
}
|
||||
if (result == 0) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (result == -1) {
|
||||
return -errno;
|
||||
}
|
||||
processed += result;
|
||||
to_recv -= result;
|
||||
if (processed != len) {
|
||||
goto retry_recv;
|
||||
}
|
||||
if (one_way->type == QB_IPC_SOCKET) {
|
||||
ctl = (struct ipc_us_control *)one_way->u.us.shared_data;
|
||||
if (ctl) {
|
||||
(void)qb_atomic_int_dec_and_test(&ctl->sent);
|
||||
}
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
/*
|
||||
* recv a message of unknow size.
|
||||
* (could use MSG_PEEK here)
|
||||
*/
|
||||
static ssize_t
|
||||
qb_ipc_us_recv_at_most(struct qb_ipc_one_way * one_way,
|
||||
void *msg, size_t len, int32_t timeout)
|
||||
{
|
||||
int32_t result;
|
||||
struct ipc_us_control *ctl = NULL;
|
||||
|
||||
retry_recv:
|
||||
result = recv(one_way->u.us.sock, msg, len, MSG_NOSIGNAL | MSG_WAITALL);
|
||||
if (timeout == -1) {
|
||||
if (result == -1 && errno == EAGAIN) {
|
||||
goto retry_recv;
|
||||
}
|
||||
}
|
||||
if (result == 0) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (result == -1) {
|
||||
return -errno;
|
||||
}
|
||||
ctl = (struct ipc_us_control *)one_way->u.us.shared_data;
|
||||
if (ctl) {
|
||||
(void)qb_atomic_int_dec_and_test(&ctl->sent);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int32_t
|
||||
qb_ipcc_us_sock_connect(const char *socket_name, int32_t * sock_pt)
|
||||
{
|
||||
int32_t request_fd;
|
||||
struct sockaddr_un address;
|
||||
int32_t res = 0;
|
||||
|
||||
#if defined(QB_SOLARIS)
|
||||
request_fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
#else
|
||||
request_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
|
||||
#endif
|
||||
if (request_fd == -1) {
|
||||
return -errno;
|
||||
}
|
||||
#ifdef SO_NOSIGPIPE
|
||||
socket_nosigpipe(request_fd);
|
||||
#endif /* SO_NOSIGPIPE */
|
||||
res = qb_sys_fd_nonblock_cloexec_set(request_fd);
|
||||
if (res < 0) {
|
||||
goto error_connect;
|
||||
}
|
||||
|
||||
memset(&address, 0, sizeof(struct sockaddr_un));
|
||||
address.sun_family = AF_UNIX;
|
||||
#if defined(QB_BSD) || defined(QB_DARWIN)
|
||||
address.sun_len = SUN_LEN(&address);
|
||||
#endif
|
||||
|
||||
#if defined(QB_LINUX)
|
||||
snprintf(address.sun_path + 1, UNIX_PATH_MAX - 1, "%s", socket_name);
|
||||
#else
|
||||
snprintf(address.sun_path, UNIX_PATH_MAX, "%s/%s", SOCKETDIR,
|
||||
socket_name);
|
||||
#endif
|
||||
if (connect(request_fd, (struct sockaddr *)&address,
|
||||
QB_SUN_LEN(&address)) == -1) {
|
||||
res = -errno;
|
||||
goto error_connect;
|
||||
}
|
||||
|
||||
*sock_pt = request_fd;
|
||||
return 0;
|
||||
|
||||
error_connect:
|
||||
close(request_fd);
|
||||
*sock_pt = -1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcc_us_sock_close(int32_t sock)
|
||||
{
|
||||
shutdown(sock, SHUT_RDWR);
|
||||
close(sock);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
|
||||
struct qb_ipc_connection_response *r)
|
||||
{
|
||||
int32_t res;
|
||||
struct qb_ipc_connection_request request;
|
||||
|
||||
res = qb_ipcc_us_sock_connect(c->name, &c->setup.u.us.sock);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
request.hdr.id = QB_IPC_MSG_AUTHENTICATE;
|
||||
request.hdr.size = sizeof(request);
|
||||
request.max_msg_size = c->setup.max_msg_size;
|
||||
res = qb_ipc_us_send(&c->setup, &request, request.hdr.size);
|
||||
if (res < 0) {
|
||||
qb_ipcc_us_sock_close(c->setup.u.us.sock);
|
||||
return res;
|
||||
}
|
||||
|
||||
res =
|
||||
qb_ipc_us_recv(&c->setup, r,
|
||||
sizeof(struct qb_ipc_connection_response), -1);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (r->hdr.error != 0) {
|
||||
return r->hdr.error;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
qb_ipcc_us_disconnect(struct qb_ipcc_connection *c)
|
||||
{
|
||||
munmap(c->request.u.us.shared_data, sizeof(struct ipc_us_control));
|
||||
unlink(c->request.u.us.shared_file_name);
|
||||
close(c->request.u.us.sock);
|
||||
close(c->event.u.us.sock);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcc_us_connect(struct qb_ipcc_connection *c,
|
||||
struct qb_ipc_connection_response *r)
|
||||
{
|
||||
int32_t res;
|
||||
struct qb_ipc_event_connection_request request;
|
||||
char path[PATH_MAX];
|
||||
int32_t fd_hdr;
|
||||
struct ipc_us_control *ctl;
|
||||
|
||||
c->needs_sock_for_poll = QB_FALSE;
|
||||
c->funcs.send = qb_ipc_us_send;
|
||||
c->funcs.sendv = qb_ipc_us_sendv;
|
||||
c->funcs.recv = qb_ipc_us_recv_at_most;
|
||||
c->funcs.fc_get = qb_ipc_us_fc_get;
|
||||
c->funcs.disconnect = qb_ipcc_us_disconnect;
|
||||
|
||||
c->request.u.us.sock = c->setup.u.us.sock;
|
||||
c->response.u.us.sock = c->setup.u.us.sock;
|
||||
c->setup.u.us.sock = -1;
|
||||
|
||||
fd_hdr = qb_sys_mmap_file_open(path, r->request,
|
||||
sizeof(struct ipc_us_control), O_RDWR);
|
||||
if (fd_hdr < 0) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "couldn't open file for mmap");
|
||||
return res;
|
||||
}
|
||||
(void)strlcpy(c->request.u.us.shared_file_name, r->request, NAME_MAX);
|
||||
c->request.u.us.shared_data = mmap(0,
|
||||
sizeof(struct ipc_us_control),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
fd_hdr, 0);
|
||||
|
||||
if (c->request.u.us.shared_data == MAP_FAILED) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "couldn't create mmap for header");
|
||||
goto cleanup_hdr;
|
||||
}
|
||||
|
||||
ctl = (struct ipc_us_control *)c->request.u.us.shared_data;
|
||||
ctl->sent = 0;
|
||||
ctl->flow_control = 0;
|
||||
|
||||
close(fd_hdr);
|
||||
|
||||
res = qb_ipcc_us_sock_connect(c->name, &c->event.u.us.sock);
|
||||
if (res != 0) {
|
||||
goto cleanup_hdr;
|
||||
}
|
||||
|
||||
request.hdr.id = QB_IPC_MSG_NEW_EVENT_SOCK;
|
||||
request.hdr.size = sizeof(request);
|
||||
request.connection = r->connection;
|
||||
res = qb_ipc_us_send(&c->event, &request, request.hdr.size);
|
||||
if (res < 0) {
|
||||
qb_ipcc_us_sock_close(c->event.u.us.sock);
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_hdr:
|
||||
close(fd_hdr);
|
||||
unlink(r->request);
|
||||
munmap(c->request.u.us.shared_data, sizeof(struct ipc_us_control));
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
**************************************************************************
|
||||
* SERVER
|
||||
*/
|
||||
|
||||
int32_t
|
||||
qb_ipcs_us_publish(struct qb_ipcs_service * s)
|
||||
{
|
||||
struct sockaddr_un un_addr;
|
||||
int32_t res;
|
||||
|
||||
/*
|
||||
* Create socket for IPC clients, name socket, listen for connections
|
||||
*/
|
||||
#if defined(QB_SOLARIS)
|
||||
s->server_sock = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
#else
|
||||
s->server_sock = socket(PF_LOCAL, SOCK_STREAM, 0);
|
||||
#endif
|
||||
if (s->server_sock == -1) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "Cannot create server socket");
|
||||
return res;
|
||||
}
|
||||
|
||||
res = qb_sys_fd_nonblock_cloexec_set(s->server_sock);
|
||||
if (res < 0) {
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
memset(&un_addr, 0, sizeof(struct sockaddr_un));
|
||||
un_addr.sun_family = AF_UNIX;
|
||||
#if defined(QB_BSD) || defined(QB_DARWIN)
|
||||
un_addr.sun_len = SUN_LEN(&un_addr);
|
||||
#endif
|
||||
|
||||
qb_util_log(LOG_INFO, "server name: %s", s->name);
|
||||
#if defined(QB_LINUX)
|
||||
snprintf(un_addr.sun_path + 1, UNIX_PATH_MAX - 1, "%s", s->name);
|
||||
#else
|
||||
{
|
||||
struct stat stat_out;
|
||||
res = stat(SOCKETDIR, &stat_out);
|
||||
if (res == -1 || (res == 0 && !S_ISDIR(stat_out.st_mode))) {
|
||||
res = -errno;
|
||||
qb_util_log(LOG_CRIT,
|
||||
"Required directory not present %s",
|
||||
SOCKETDIR);
|
||||
goto error_close;
|
||||
}
|
||||
snprintf(un_addr.sun_path, UNIX_PATH_MAX, "%s/%s", SOCKETDIR,
|
||||
s->name);
|
||||
unlink(un_addr.sun_path);
|
||||
}
|
||||
#endif
|
||||
|
||||
res = bind(s->server_sock, (struct sockaddr *)&un_addr,
|
||||
QB_SUN_LEN(&un_addr));
|
||||
if (res) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "Could not bind AF_UNIX (%s)",
|
||||
un_addr.sun_path);
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow everyone to write to the socket since the IPC layer handles
|
||||
* security automatically
|
||||
*/
|
||||
#if !defined(QB_LINUX)
|
||||
res = chmod(un_addr.sun_path, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
#endif
|
||||
if (listen(s->server_sock, SERVER_BACKLOG) == -1) {
|
||||
qb_util_perror(LOG_ERR, "socket listen failed");
|
||||
}
|
||||
|
||||
res = s->poll_fns.dispatch_add(s->poll_priority, s->server_sock,
|
||||
POLLIN | POLLPRI | POLLNVAL,
|
||||
s, qb_ipcs_us_connection_acceptor);
|
||||
return res;
|
||||
|
||||
error_close:
|
||||
close(s->server_sock);
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcs_us_withdraw(struct qb_ipcs_service * s)
|
||||
{
|
||||
qb_util_log(LOG_INFO, "withdrawing server sockets");
|
||||
shutdown(s->server_sock, SHUT_RDWR);
|
||||
close(s->server_sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
handle_new_connection(struct qb_ipcs_service *s,
|
||||
int32_t auth_result,
|
||||
int32_t sock,
|
||||
void *msg, size_t len, struct ipc_auth_ugp *ugp)
|
||||
{
|
||||
struct qb_ipcs_connection *c = NULL;
|
||||
struct qb_ipc_connection_request *req = msg;
|
||||
int32_t res = auth_result;
|
||||
int32_t res2 = 0;
|
||||
struct qb_ipc_connection_response response;
|
||||
|
||||
c = qb_ipcs_connection_alloc(s);
|
||||
if (c == NULL) {
|
||||
qb_ipcc_us_sock_close(sock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
c->receive_buf = malloc(req->max_msg_size);
|
||||
if (c->receive_buf == NULL) {
|
||||
free(c);
|
||||
qb_ipcc_us_sock_close(sock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
c->setup.u.us.sock = sock;
|
||||
c->request.max_msg_size = req->max_msg_size;
|
||||
c->response.max_msg_size = req->max_msg_size;
|
||||
c->event.max_msg_size = req->max_msg_size;
|
||||
c->pid = ugp->pid;
|
||||
c->euid = ugp->uid;
|
||||
c->egid = ugp->gid;
|
||||
c->stats.client_pid = ugp->pid;
|
||||
|
||||
if (auth_result == 0 && c->service->serv_fns.connection_accept) {
|
||||
res = c->service->serv_fns.connection_accept(c,
|
||||
c->euid, c->egid);
|
||||
}
|
||||
if (res != 0) {
|
||||
goto send_response;
|
||||
}
|
||||
|
||||
qb_util_log(LOG_INFO, "IPC credentials authenticated");
|
||||
|
||||
memset(&response, 0, sizeof(response));
|
||||
if (s->funcs.connect) {
|
||||
res = s->funcs.connect(s, c, &response);
|
||||
if (res != 0) {
|
||||
goto send_response;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The connection is good, add it to the active connection list
|
||||
*/
|
||||
c->state = QB_IPCS_CONNECTION_ACTIVE;
|
||||
qb_list_add(&c->list, &s->connections);
|
||||
|
||||
if (s->needs_sock_for_poll) {
|
||||
qb_ipcs_connection_ref(c);
|
||||
res = s->poll_fns.dispatch_add(s->poll_priority,
|
||||
c->setup.u.us.sock,
|
||||
POLLIN | POLLPRI | POLLNVAL,
|
||||
c,
|
||||
qb_ipcs_dispatch_connection_request);
|
||||
}
|
||||
if (s->type == QB_IPC_SOCKET) {
|
||||
c->request.u.us.sock = c->setup.u.us.sock;
|
||||
c->response.u.us.sock = c->setup.u.us.sock;
|
||||
res = s->poll_fns.dispatch_add(s->poll_priority,
|
||||
c->request.u.us.sock,
|
||||
POLLIN | POLLPRI | POLLNVAL,
|
||||
c,
|
||||
qb_ipcs_dispatch_connection_request);
|
||||
if (res < 0) {
|
||||
qb_util_log(LOG_ERR,
|
||||
"Error adding socket to mainloop.");
|
||||
}
|
||||
}
|
||||
|
||||
send_response:
|
||||
response.hdr.id = QB_IPC_MSG_AUTHENTICATE;
|
||||
response.hdr.size = sizeof(response);
|
||||
response.hdr.error = res;
|
||||
if (res == 0) {
|
||||
response.connection = (intptr_t) c;
|
||||
response.connection_type = s->type;
|
||||
response.max_msg_size = c->request.max_msg_size;
|
||||
s->stats.active_connections++;
|
||||
}
|
||||
|
||||
res2 = qb_ipc_us_send(&c->setup, &response, response.hdr.size);
|
||||
if (res == 0 && res2 != response.hdr.size) {
|
||||
res = res2;
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
qb_ipcs_connection_ref(c);
|
||||
if (s->serv_fns.connection_created) {
|
||||
s->serv_fns.connection_created(c);
|
||||
}
|
||||
if (c->state == QB_IPCS_CONNECTION_ACTIVE) {
|
||||
c->state = QB_IPCS_CONNECTION_ESTABLISHED;
|
||||
}
|
||||
qb_ipcs_connection_unref(c);
|
||||
} else {
|
||||
if (res == -EACCES) {
|
||||
qb_util_log(LOG_ERR, "Invalid IPC credentials.");
|
||||
} else {
|
||||
qb_util_perror(LOG_ERR, "Error in connection setup");
|
||||
}
|
||||
qb_ipcs_disconnect(c);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_connection_new_sock(struct qb_ipcs_service *s, int32_t sock, void *msg)
|
||||
{
|
||||
struct qb_ipcs_connection *c = NULL;
|
||||
struct qb_ipc_event_connection_request *req = msg;
|
||||
|
||||
c = (struct qb_ipcs_connection *)req->connection;
|
||||
c->event.u.us.sock = sock;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
qb_ipcs_uc_recv_and_auth(int32_t sock, void *msg, size_t len,
|
||||
struct ipc_auth_ugp *ugp)
|
||||
{
|
||||
int32_t res = 0;
|
||||
struct msghdr msg_recv;
|
||||
struct iovec iov_recv;
|
||||
|
||||
#ifdef QB_LINUX
|
||||
char cmsg_cred[CMSG_SPACE(sizeof(struct ucred))];
|
||||
int off = 0;
|
||||
int on = 1;
|
||||
#endif
|
||||
msg_recv.msg_flags = 0;
|
||||
msg_recv.msg_iov = &iov_recv;
|
||||
msg_recv.msg_iovlen = 1;
|
||||
msg_recv.msg_name = 0;
|
||||
msg_recv.msg_namelen = 0;
|
||||
#ifdef QB_LINUX
|
||||
msg_recv.msg_control = (void *)cmsg_cred;
|
||||
msg_recv.msg_controllen = sizeof(cmsg_cred);
|
||||
#endif
|
||||
#ifdef QB_SOLARIS
|
||||
msg_recv.msg_accrights = 0;
|
||||
msg_recv.msg_accrightslen = 0;
|
||||
#endif /* QB_SOLARIS */
|
||||
|
||||
iov_recv.iov_base = msg;
|
||||
iov_recv.iov_len = len;
|
||||
#ifdef QB_LINUX
|
||||
setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
|
||||
#endif
|
||||
|
||||
res = qb_ipc_us_recv_msghdr(sock, &msg_recv, msg, len);
|
||||
if (res < 0) {
|
||||
goto cleanup_and_return;
|
||||
}
|
||||
if (res != len) {
|
||||
res = -EIO;
|
||||
goto cleanup_and_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* currently support getpeerucred, getpeereid, and SO_PASSCRED credential
|
||||
* retrieval mechanisms for various Platforms
|
||||
*/
|
||||
#ifdef HAVE_GETPEERUCRED
|
||||
/*
|
||||
* Solaris and some BSD systems
|
||||
*/
|
||||
{
|
||||
ucred_t *uc = NULL;
|
||||
|
||||
if (getpeerucred(sock, &uc) == 0) {
|
||||
res = 0;
|
||||
ugp->uid = ucred_geteuid(uc);
|
||||
ugp->gid = ucred_getegid(uc);
|
||||
ugp->pid = ucred_getpid(uc);
|
||||
ucred_free(uc);
|
||||
} else {
|
||||
res = -errno;
|
||||
}
|
||||
}
|
||||
#elif HAVE_GETPEEREID
|
||||
/*
|
||||
* Usually MacOSX systems
|
||||
*/
|
||||
{
|
||||
/*
|
||||
* TODO get the peer's pid.
|
||||
* c->pid = ?;
|
||||
*/
|
||||
if (getpeereid(sock, &ugp->uid, &ugp->gid) == 0) {
|
||||
res = 0;
|
||||
} else {
|
||||
res = -errno;
|
||||
}
|
||||
}
|
||||
|
||||
#elif SO_PASSCRED
|
||||
/*
|
||||
* Usually Linux systems
|
||||
*/
|
||||
{
|
||||
struct ucred cred;
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg_recv);
|
||||
assert(cmsg != NULL);
|
||||
if (CMSG_DATA(cmsg)) {
|
||||
memcpy(&cred, CMSG_DATA(cmsg), sizeof(struct ucred));
|
||||
res = 0;
|
||||
ugp->pid = cred.pid;
|
||||
ugp->uid = cred.uid;
|
||||
ugp->gid = cred.gid;
|
||||
} else {
|
||||
res = -EBADMSG;
|
||||
}
|
||||
}
|
||||
#else /* no credentials */
|
||||
ugp->pid = 0;
|
||||
ugp->uid = 0;
|
||||
ugp->gid = 0;
|
||||
res = -ENOTSUP;
|
||||
#endif /* no credentials */
|
||||
|
||||
cleanup_and_return:
|
||||
|
||||
#ifdef QB_LINUX
|
||||
setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &off, sizeof(off));
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
qb_ipcs_us_connection_acceptor(int fd, int revent, void *data)
|
||||
{
|
||||
struct sockaddr_un un_addr;
|
||||
int32_t new_fd;
|
||||
struct qb_ipcs_service *s = (struct qb_ipcs_service *)data;
|
||||
int32_t res;
|
||||
struct qb_ipc_connection_request setup_msg;
|
||||
struct ipc_auth_ugp ugp;
|
||||
socklen_t addrlen = sizeof(struct sockaddr_un);
|
||||
|
||||
retry_accept:
|
||||
errno = 0;
|
||||
new_fd = accept(fd, (struct sockaddr *)&un_addr, &addrlen);
|
||||
if (new_fd == -1 && errno == EINTR) {
|
||||
goto retry_accept;
|
||||
}
|
||||
|
||||
if (new_fd == -1 && errno == EBADF) {
|
||||
qb_util_perror(LOG_ERR,
|
||||
"Could not accept client connection from fd:%d",
|
||||
fd);
|
||||
return -1;
|
||||
}
|
||||
if (new_fd == -1) {
|
||||
qb_util_perror(LOG_ERR, "Could not accept client connection");
|
||||
/* This is an error, but -1 would indicate disconnect
|
||||
* from the poll loop
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = qb_sys_fd_nonblock_cloexec_set(new_fd);
|
||||
if (res < 0) {
|
||||
close(new_fd);
|
||||
/* This is an error, but -1 would indicate disconnect
|
||||
* from the poll loop
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = qb_ipcs_uc_recv_and_auth(new_fd, &setup_msg, sizeof(setup_msg),
|
||||
&ugp);
|
||||
|
||||
if (setup_msg.hdr.id == QB_IPC_MSG_AUTHENTICATE) {
|
||||
(void)handle_new_connection(s, res, new_fd, &setup_msg,
|
||||
sizeof(setup_msg), &ugp);
|
||||
} else if (setup_msg.hdr.id == QB_IPC_MSG_NEW_EVENT_SOCK) {
|
||||
if (res == 0) {
|
||||
handle_connection_new_sock(s, new_fd, &setup_msg);
|
||||
} else {
|
||||
close(new_fd);
|
||||
}
|
||||
} else {
|
||||
close(new_fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
qb_ipcs_us_connect(struct qb_ipcs_service *s,
|
||||
struct qb_ipcs_connection *c,
|
||||
struct qb_ipc_connection_response *r)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int32_t fd_hdr;
|
||||
int32_t res = 0;
|
||||
struct ipc_us_control *ctl;
|
||||
|
||||
qb_util_log(LOG_DEBUG, "connecting to client [%d]", c->pid);
|
||||
|
||||
snprintf(r->request, NAME_MAX, "qb-%s-control-%d-%d",
|
||||
s->name, c->pid, c->setup.u.us.sock);
|
||||
|
||||
fd_hdr = qb_sys_mmap_file_open(path, r->request,
|
||||
sizeof(struct ipc_us_control),
|
||||
O_CREAT | O_TRUNC | O_RDWR);
|
||||
if (fd_hdr < 0) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "couldn't create file for mmap");
|
||||
return res;
|
||||
}
|
||||
(void)strlcpy(r->request, path, PATH_MAX);
|
||||
(void)strlcpy(c->request.u.us.shared_file_name, r->request, NAME_MAX);
|
||||
|
||||
c->request.u.us.shared_data = mmap(0,
|
||||
sizeof(struct ipc_us_control),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
fd_hdr, 0);
|
||||
|
||||
if (c->request.u.us.shared_data == MAP_FAILED) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "couldn't create mmap for header");
|
||||
goto cleanup_hdr;
|
||||
}
|
||||
|
||||
ctl = (struct ipc_us_control *)c->request.u.us.shared_data;
|
||||
ctl->sent = 0;
|
||||
ctl->flow_control = 0;
|
||||
|
||||
close(fd_hdr);
|
||||
return res;
|
||||
|
||||
cleanup_hdr:
|
||||
close(fd_hdr);
|
||||
unlink(r->request);
|
||||
munmap(c->request.u.us.shared_data, sizeof(struct ipc_us_control));
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
qb_ipc_us_fc_set(struct qb_ipc_one_way *one_way, int32_t fc_enable)
|
||||
{
|
||||
struct ipc_us_control *ctl =
|
||||
(struct ipc_us_control *)one_way->u.us.shared_data;
|
||||
|
||||
qb_util_log(LOG_TRACE, "setting fc to %d", fc_enable);
|
||||
qb_atomic_int_set(&ctl->flow_control, fc_enable);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
qb_ipc_us_fc_get(struct qb_ipc_one_way *one_way)
|
||||
{
|
||||
struct ipc_us_control *ctl =
|
||||
(struct ipc_us_control *)one_way->u.us.shared_data;
|
||||
|
||||
return qb_atomic_int_get(&ctl->flow_control);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_us_q_len_get(struct qb_ipc_one_way *one_way)
|
||||
{
|
||||
struct ipc_us_control *ctl =
|
||||
(struct ipc_us_control *)one_way->u.us.shared_data;
|
||||
return qb_atomic_int_get(&ctl->sent);
|
||||
}
|
||||
|
||||
static void
|
||||
qb_ipcs_us_disconnect(struct qb_ipcs_connection *c)
|
||||
{
|
||||
munmap(c->request.u.us.shared_data, sizeof(struct ipc_us_control));
|
||||
unlink(c->request.u.us.shared_file_name);
|
||||
|
||||
close(c->request.u.us.sock);
|
||||
close(c->event.u.us.sock);
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_us_init(struct qb_ipcs_service *s)
|
||||
{
|
||||
s->funcs.connect = qb_ipcs_us_connect;
|
||||
s->funcs.disconnect = qb_ipcs_us_disconnect;
|
||||
|
||||
s->funcs.recv = qb_ipc_us_recv_at_most;
|
||||
s->funcs.peek = NULL;
|
||||
s->funcs.reclaim = NULL;
|
||||
s->funcs.send = qb_ipc_us_send;
|
||||
s->funcs.sendv = qb_ipc_us_sendv;
|
||||
|
||||
s->funcs.fc_set = qb_ipc_us_fc_set;
|
||||
s->funcs.q_len_get = qb_ipc_us_q_len_get;
|
||||
|
||||
s->needs_sock_for_poll = QB_FALSE;
|
||||
}
|
||||
383
lib/ipcc.c
Normal file
383
lib/ipcc.c
Normal file
@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#ifdef HAVE_MQUEUE_H
|
||||
#include <mqueue.h>
|
||||
#endif /* HAVE_MQUEUE_H */
|
||||
#include "ipc_int.h"
|
||||
#include "util_int.h"
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbipcc.h>
|
||||
|
||||
qb_ipcc_connection_t *
|
||||
qb_ipcc_connect(const char *name, size_t max_msg_size)
|
||||
{
|
||||
int32_t res;
|
||||
qb_ipcc_connection_t *c = NULL;
|
||||
struct qb_ipc_connection_response response;
|
||||
|
||||
c = calloc(1, sizeof(struct qb_ipcc_connection));
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c->setup.max_msg_size = max_msg_size;
|
||||
(void)strlcpy(c->name, name, NAME_MAX);
|
||||
res = qb_ipcc_us_setup_connect(c, &response);
|
||||
if (res < 0) {
|
||||
goto disconnect_and_cleanup;
|
||||
}
|
||||
c->response.type = response.connection_type;
|
||||
c->request.type = response.connection_type;
|
||||
c->event.type = response.connection_type;
|
||||
c->setup.type = response.connection_type;
|
||||
|
||||
c->response.max_msg_size = response.max_msg_size;
|
||||
c->request.max_msg_size = response.max_msg_size;
|
||||
c->event.max_msg_size = response.max_msg_size;
|
||||
c->receive_buf = malloc(response.max_msg_size);
|
||||
c->fc_enable_max = 1;
|
||||
if (c->receive_buf == NULL) {
|
||||
res = -ENOMEM;
|
||||
goto disconnect_and_cleanup;
|
||||
}
|
||||
|
||||
switch (c->request.type) {
|
||||
case QB_IPC_SHM:
|
||||
res = qb_ipcc_shm_connect(c, &response);
|
||||
break;
|
||||
case QB_IPC_POSIX_MQ:
|
||||
#ifdef HAVE_POSIX_MQ
|
||||
res = qb_ipcc_pmq_connect(c, &response);
|
||||
#else
|
||||
res = -ENOTSUP;
|
||||
#endif /* HAVE_POSIX_MQ */
|
||||
break;
|
||||
case QB_IPC_SYSV_MQ:
|
||||
#ifdef HAVE_SYSV_MQ
|
||||
res = qb_ipcc_smq_connect(c, &response);
|
||||
#else
|
||||
res = -ENOTSUP;
|
||||
#endif /* HAVE_SYSV_MQ */
|
||||
break;
|
||||
case QB_IPC_SOCKET:
|
||||
res = qb_ipcc_us_connect(c, &response);
|
||||
break;
|
||||
default:
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (res != 0) {
|
||||
goto disconnect_and_cleanup;
|
||||
}
|
||||
c->is_connected = QB_TRUE;
|
||||
return c;
|
||||
|
||||
disconnect_and_cleanup:
|
||||
qb_ipcc_us_sock_close(c->setup.u.us.sock);
|
||||
free(c->receive_buf);
|
||||
free(c);
|
||||
errno = -res;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_ipcc_send(struct qb_ipcc_connection * c, const void *msg_ptr, size_t msg_len)
|
||||
{
|
||||
ssize_t res;
|
||||
ssize_t res2;
|
||||
|
||||
if (c == NULL || msg_len > c->request.max_msg_size) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (c->funcs.fc_get) {
|
||||
res = c->funcs.fc_get(&c->request);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
} else if (res > 0 && res <= c->fc_enable_max) {
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
/*
|
||||
* we can transmit
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
res = c->funcs.send(&c->request, msg_ptr, msg_len);
|
||||
if (res == msg_len && c->needs_sock_for_poll) {
|
||||
do {
|
||||
res2 = qb_ipc_us_send(&c->setup, msg_ptr, 1);
|
||||
} while (res2 == -EAGAIN);
|
||||
if (res2 == -EPIPE) {
|
||||
c->is_connected = QB_FALSE;
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (res2 != 1) {
|
||||
res = res2;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcc_fc_enable_max_set(struct qb_ipcc_connection * c, uint32_t max)
|
||||
{
|
||||
if (c == NULL || max > 2) {
|
||||
return -EINVAL;
|
||||
}
|
||||
c->fc_enable_max = max;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_ipcc_sendv(struct qb_ipcc_connection * c, const struct iovec * iov,
|
||||
size_t iov_len)
|
||||
{
|
||||
int32_t total_size = 0;
|
||||
int32_t i;
|
||||
int32_t res;
|
||||
int32_t res2;
|
||||
|
||||
for (i = 0; i < iov_len; i++) {
|
||||
total_size += iov[i].iov_len;
|
||||
}
|
||||
if (c == NULL || total_size > c->request.max_msg_size) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (c->funcs.fc_get) {
|
||||
res = c->funcs.fc_get(&c->request);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
} else if (res > 0 && res <= c->fc_enable_max) {
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
/*
|
||||
* we can transmit
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
res = c->funcs.sendv(&c->request, iov, iov_len);
|
||||
if (res > 0 && c->needs_sock_for_poll) {
|
||||
do {
|
||||
res2 = qb_ipc_us_send(&c->setup, &res, 1);
|
||||
} while (res2 == -EAGAIN);
|
||||
if (res2 == -EPIPE) {
|
||||
c->is_connected = QB_FALSE;
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (res2 != 1) {
|
||||
res = res2;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_ipcc_recv(struct qb_ipcc_connection * c, void *msg_ptr,
|
||||
size_t msg_len, int32_t ms_timeout)
|
||||
{
|
||||
int32_t res = 0;
|
||||
int32_t res2 = 0;
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = c->funcs.recv(&c->response, msg_ptr, msg_len, ms_timeout);
|
||||
if ((res == -EAGAIN || res == -ETIMEDOUT) && c->needs_sock_for_poll) {
|
||||
res2 = qb_ipc_us_recv_ready(&c->setup, 0);
|
||||
if (res2 < 0) {
|
||||
if (res2 == -ENOTCONN) {
|
||||
c->is_connected = QB_FALSE;
|
||||
}
|
||||
return res2;
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_ipcc_sendv_recv(qb_ipcc_connection_t * c,
|
||||
const struct iovec * iov, uint32_t iov_len,
|
||||
void *res_msg, size_t res_len, int32_t ms_timeout)
|
||||
{
|
||||
ssize_t res = 0;
|
||||
int32_t timeout_now;
|
||||
int32_t timeout_rem = ms_timeout;
|
||||
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (c->funcs.fc_get) {
|
||||
res = c->funcs.fc_get(&c->request);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
} else if (res > 0 && res <= c->fc_enable_max) {
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
/*
|
||||
* we can transmit
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
res = qb_ipcc_sendv(c, iov, iov_len);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
do {
|
||||
if (timeout_rem > QB_IPC_MAX_WAIT_MS || ms_timeout == -1) {
|
||||
timeout_now = QB_IPC_MAX_WAIT_MS;
|
||||
} else {
|
||||
timeout_now = timeout_rem;
|
||||
}
|
||||
|
||||
res = qb_ipcc_recv(c, res_msg, res_len, timeout_now);
|
||||
if (res == -ETIMEDOUT) {
|
||||
if (ms_timeout < 0) {
|
||||
res = -EAGAIN;
|
||||
} else {
|
||||
timeout_rem -= timeout_now;
|
||||
if (timeout_rem > 0) {
|
||||
res = -EAGAIN;
|
||||
}
|
||||
}
|
||||
} else if (res < 0 && res != -EAGAIN) {
|
||||
errno = -res;
|
||||
qb_util_perror(LOG_DEBUG,
|
||||
"qb_ipcc_recv %d timeout:(%d/%d)",
|
||||
res, timeout_now, timeout_rem);
|
||||
}
|
||||
} while (res == -EAGAIN && c->is_connected);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcc_fd_get(struct qb_ipcc_connection * c, int32_t * fd)
|
||||
{
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (c->event.type == QB_IPC_SOCKET) {
|
||||
*fd = c->event.u.us.sock;
|
||||
} else {
|
||||
*fd = c->setup.u.us.sock;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_ipcc_event_recv(struct qb_ipcc_connection * c, void *msg_pt,
|
||||
size_t msg_len, int32_t ms_timeout)
|
||||
{
|
||||
char one_byte = 1;
|
||||
int32_t res;
|
||||
ssize_t size;
|
||||
struct qb_ipc_one_way *ow = NULL;
|
||||
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (c->needs_sock_for_poll) {
|
||||
ow = &c->setup;
|
||||
}
|
||||
if (c->event.type == QB_IPC_SOCKET) {
|
||||
ow = &c->event;
|
||||
}
|
||||
if (ow) {
|
||||
res = qb_ipc_us_recv_ready(ow, ms_timeout);
|
||||
if (res < 0) {
|
||||
if (res == -ENOTCONN) {
|
||||
c->is_connected = QB_FALSE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
size = c->funcs.recv(&c->event, msg_pt, msg_len, ms_timeout);
|
||||
if (size < 0) {
|
||||
return size;
|
||||
}
|
||||
if (c->needs_sock_for_poll) {
|
||||
res = qb_ipc_us_recv(&c->setup, &one_byte, 1, -1);
|
||||
if (res < 0) {
|
||||
if (res == -ENOTCONN) {
|
||||
c->is_connected = QB_FALSE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcc_disconnect(struct qb_ipcc_connection *c)
|
||||
{
|
||||
struct qb_ipc_one_way *ow = NULL;
|
||||
|
||||
qb_util_log(LOG_DEBUG, "%s()", __func__);
|
||||
|
||||
if (c == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->needs_sock_for_poll) {
|
||||
ow = &c->setup;
|
||||
}
|
||||
if (c->event.type == QB_IPC_SOCKET) {
|
||||
ow = &c->event;
|
||||
}
|
||||
if (ow) {
|
||||
if (qb_ipc_us_recv_ready(ow, 0) == -ENOTCONN) {
|
||||
c->is_connected = QB_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
qb_ipcc_us_sock_close(c->setup.u.us.sock);
|
||||
if (c->funcs.disconnect) {
|
||||
c->funcs.disconnect(c);
|
||||
}
|
||||
free(c->receive_buf);
|
||||
free(c);
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcc_context_set(struct qb_ipcc_connection *c, void *context)
|
||||
{
|
||||
if (c == NULL) {
|
||||
return;
|
||||
}
|
||||
c->context = context;
|
||||
}
|
||||
|
||||
void *qb_ipcc_context_get(struct qb_ipcc_connection *c)
|
||||
{
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return c->context;
|
||||
}
|
||||
767
lib/ipcs.c
Normal file
767
lib/ipcs.c
Normal file
@ -0,0 +1,767 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include "util_int.h"
|
||||
#include "ipc_int.h"
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbatomic.h>
|
||||
#include <qb/qbipcs.h>
|
||||
|
||||
static void qb_ipcs_flowcontrol_set(struct qb_ipcs_connection *c,
|
||||
int32_t fc_enable);
|
||||
|
||||
static QB_LIST_DECLARE(qb_ipc_services);
|
||||
|
||||
qb_ipcs_service_t *
|
||||
qb_ipcs_create(const char *name,
|
||||
int32_t service_id,
|
||||
enum qb_ipc_type type, struct qb_ipcs_service_handlers *handlers)
|
||||
{
|
||||
struct qb_ipcs_service *s;
|
||||
|
||||
s = calloc(1, sizeof(struct qb_ipcs_service));
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->pid = getpid();
|
||||
s->type = type;
|
||||
s->needs_sock_for_poll = QB_FALSE;
|
||||
s->poll_priority = QB_LOOP_MED;
|
||||
s->ref_count = 1;
|
||||
|
||||
s->service_id = service_id;
|
||||
(void)strlcpy(s->name, name, NAME_MAX);
|
||||
|
||||
s->serv_fns.connection_accept = handlers->connection_accept;
|
||||
s->serv_fns.connection_created = handlers->connection_created;
|
||||
s->serv_fns.msg_process = handlers->msg_process;
|
||||
s->serv_fns.connection_closed = handlers->connection_closed;
|
||||
s->serv_fns.connection_destroyed = handlers->connection_destroyed;
|
||||
|
||||
qb_list_init(&s->connections);
|
||||
qb_list_init(&s->list);
|
||||
qb_list_add(&s->list, &qb_ipc_services);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_poll_handlers_set(struct qb_ipcs_service *s,
|
||||
struct qb_ipcs_poll_handlers *handlers)
|
||||
{
|
||||
s->poll_fns.job_add = handlers->job_add;
|
||||
s->poll_fns.dispatch_add = handlers->dispatch_add;
|
||||
s->poll_fns.dispatch_mod = handlers->dispatch_mod;
|
||||
s->poll_fns.dispatch_del = handlers->dispatch_del;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcs_run(struct qb_ipcs_service *s)
|
||||
{
|
||||
int32_t res = 0;
|
||||
|
||||
if (s->poll_fns.dispatch_add == NULL ||
|
||||
s->poll_fns.dispatch_mod == NULL ||
|
||||
s->poll_fns.dispatch_del == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (s->type) {
|
||||
case QB_IPC_SOCKET:
|
||||
qb_ipcs_us_init((struct qb_ipcs_service *)s);
|
||||
break;
|
||||
case QB_IPC_SHM:
|
||||
qb_ipcs_shm_init((struct qb_ipcs_service *)s);
|
||||
break;
|
||||
case QB_IPC_POSIX_MQ:
|
||||
#ifdef HAVE_POSIX_MQ
|
||||
qb_ipcs_pmq_init((struct qb_ipcs_service *)s);
|
||||
#else
|
||||
res = -ENOTSUP;
|
||||
#endif /* HAVE_POSIX_MQ */
|
||||
break;
|
||||
case QB_IPC_SYSV_MQ:
|
||||
#ifdef HAVE_SYSV_MQ
|
||||
qb_ipcs_smq_init((struct qb_ipcs_service *)s);
|
||||
#else
|
||||
res = -ENOTSUP;
|
||||
#endif /* HAVE_SYSV_MQ */
|
||||
break;
|
||||
default:
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (res < 0) {
|
||||
qb_ipcs_unref(s);
|
||||
return res;
|
||||
}
|
||||
res = qb_ipcs_us_publish(s);
|
||||
if (res < 0) {
|
||||
(void)qb_ipcs_us_withdraw(s);
|
||||
qb_ipcs_unref(s);
|
||||
return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_modify_dispatch_descriptor_(struct qb_ipcs_connection *c)
|
||||
{
|
||||
qb_ipcs_dispatch_mod_fn disp_mod = c->service->poll_fns.dispatch_mod;
|
||||
|
||||
if (c->service->type == QB_IPC_POSIX_MQ
|
||||
&& !c->service->needs_sock_for_poll) {
|
||||
#ifdef HAVE_MQUEUE_H
|
||||
return disp_mod(c->service->poll_priority,
|
||||
(int32_t) c->request.u.pmq.q,
|
||||
c->poll_events, c,
|
||||
qb_ipcs_dispatch_service_request);
|
||||
#endif /* HAVE_MQUEUE_H */
|
||||
} else if (c->service->type == QB_IPC_SOCKET) {
|
||||
return disp_mod(c->service->poll_priority,
|
||||
c->event.u.us.sock,
|
||||
c->poll_events, c,
|
||||
qb_ipcs_dispatch_connection_request);
|
||||
} else {
|
||||
return disp_mod(c->service->poll_priority,
|
||||
c->setup.u.us.sock,
|
||||
c->poll_events, c,
|
||||
qb_ipcs_dispatch_connection_request);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_request_rate_limit(struct qb_ipcs_service *s,
|
||||
enum qb_ipcs_rate_limit rl)
|
||||
{
|
||||
struct qb_ipcs_connection *c;
|
||||
enum qb_loop_priority old_p = s->poll_priority;
|
||||
struct qb_list_head *pos;
|
||||
struct qb_list_head *n;
|
||||
|
||||
switch (rl) {
|
||||
case QB_IPCS_RATE_FAST:
|
||||
s->poll_priority = QB_LOOP_HIGH;
|
||||
break;
|
||||
case QB_IPCS_RATE_SLOW:
|
||||
case QB_IPCS_RATE_OFF:
|
||||
case QB_IPCS_RATE_OFF_2:
|
||||
s->poll_priority = QB_LOOP_LOW;
|
||||
break;
|
||||
default:
|
||||
case QB_IPCS_RATE_NORMAL:
|
||||
s->poll_priority = QB_LOOP_MED;
|
||||
break;
|
||||
}
|
||||
|
||||
for (pos = s->connections.next, n = pos->next;
|
||||
pos != &s->connections; pos = n, n = pos->next) {
|
||||
|
||||
c = qb_list_entry(pos, struct qb_ipcs_connection, list);
|
||||
qb_ipcs_connection_ref(c);
|
||||
|
||||
if (rl == QB_IPCS_RATE_OFF) {
|
||||
qb_ipcs_flowcontrol_set(c, 1);
|
||||
} else if (rl == QB_IPCS_RATE_OFF_2) {
|
||||
qb_ipcs_flowcontrol_set(c, 2);
|
||||
} else {
|
||||
qb_ipcs_flowcontrol_set(c, QB_FALSE);
|
||||
}
|
||||
if (old_p != s->poll_priority) {
|
||||
(void)_modify_dispatch_descriptor_(c);
|
||||
}
|
||||
qb_ipcs_connection_unref(c);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_ref(struct qb_ipcs_service *s)
|
||||
{
|
||||
qb_atomic_int_inc(&s->ref_count);
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_unref(struct qb_ipcs_service *s)
|
||||
{
|
||||
int32_t free_it;
|
||||
struct qb_ipcs_connection *c = NULL;
|
||||
struct qb_list_head *pos;
|
||||
struct qb_list_head *n;
|
||||
|
||||
assert(s->ref_count > 0);
|
||||
free_it = qb_atomic_int_dec_and_test(&s->ref_count);
|
||||
if (free_it) {
|
||||
qb_util_log(LOG_DEBUG, "%s() - destroying", __func__);
|
||||
for (pos = s->connections.next, n = pos->next;
|
||||
pos != &s->connections; pos = n, n = pos->next) {
|
||||
c = qb_list_entry(pos, struct qb_ipcs_connection, list);
|
||||
if (c == NULL) {
|
||||
continue;
|
||||
}
|
||||
qb_ipcs_disconnect(c);
|
||||
}
|
||||
(void)qb_ipcs_us_withdraw(s);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_destroy(struct qb_ipcs_service *s)
|
||||
{
|
||||
qb_ipcs_unref(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* connection API
|
||||
*/
|
||||
|
||||
ssize_t
|
||||
qb_ipcs_response_send(struct qb_ipcs_connection *c, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
ssize_t res;
|
||||
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
qb_ipcs_connection_ref(c);
|
||||
res = c->service->funcs.send(&c->response, data, size);
|
||||
if (res == size) {
|
||||
c->stats.responses++;
|
||||
} else if (res == -EAGAIN || res == -ETIMEDOUT) {
|
||||
c->stats.send_retries++;
|
||||
}
|
||||
qb_ipcs_connection_unref(c);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_ipcs_response_sendv(struct qb_ipcs_connection * c, const struct iovec * iov,
|
||||
size_t iov_len)
|
||||
{
|
||||
ssize_t res;
|
||||
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
qb_ipcs_connection_ref(c);
|
||||
res = c->service->funcs.sendv(&c->response, iov, iov_len);
|
||||
if (res > 0) {
|
||||
c->stats.responses++;
|
||||
} else if (res == -EAGAIN || res == -ETIMEDOUT) {
|
||||
c->stats.send_retries++;
|
||||
}
|
||||
qb_ipcs_connection_unref(c);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
resend_event_notifications(struct qb_ipcs_connection *c)
|
||||
{
|
||||
ssize_t res = 0;
|
||||
|
||||
if (c->outstanding_notifiers > 0) {
|
||||
res = qb_ipc_us_send(&c->setup, &c->outstanding_notifiers,
|
||||
c->outstanding_notifiers);
|
||||
}
|
||||
if (res > 0) {
|
||||
c->outstanding_notifiers -= res;
|
||||
}
|
||||
assert(c->outstanding_notifiers >= 0);
|
||||
if (c->outstanding_notifiers == 0) {
|
||||
c->poll_events = POLLIN | POLLPRI | POLLNVAL;
|
||||
(void)_modify_dispatch_descriptor_(c);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
new_event_notification(struct qb_ipcs_connection * c)
|
||||
{
|
||||
ssize_t res = 0;
|
||||
|
||||
if (!c->service->needs_sock_for_poll) {
|
||||
return res;
|
||||
}
|
||||
|
||||
assert(c->outstanding_notifiers >= 0);
|
||||
if (c->outstanding_notifiers > 0) {
|
||||
c->outstanding_notifiers++;
|
||||
} else {
|
||||
res = qb_ipc_us_send(&c->setup, &c->outstanding_notifiers, 1);
|
||||
if (res == 1) {
|
||||
return res;
|
||||
}
|
||||
/*
|
||||
* notify the client later, when we can.
|
||||
*/
|
||||
c->outstanding_notifiers++;
|
||||
c->poll_events = POLLOUT | POLLIN | POLLPRI | POLLNVAL;
|
||||
(void)_modify_dispatch_descriptor_(c);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_ipcs_event_send(struct qb_ipcs_connection * c, const void *data, size_t size)
|
||||
{
|
||||
ssize_t res;
|
||||
ssize_t resn;
|
||||
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
qb_ipcs_connection_ref(c);
|
||||
|
||||
res = c->service->funcs.send(&c->event, data, size);
|
||||
if (res == size) {
|
||||
c->stats.events++;
|
||||
resn = new_event_notification(c);
|
||||
if (resn < 0 && resn != -EAGAIN) {
|
||||
errno = -resn;
|
||||
qb_util_perror(LOG_WARNING, "new_event_notification");
|
||||
}
|
||||
}
|
||||
|
||||
qb_ipcs_connection_unref(c);
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_ipcs_event_sendv(struct qb_ipcs_connection * c,
|
||||
const struct iovec * iov, size_t iov_len)
|
||||
{
|
||||
ssize_t res;
|
||||
ssize_t resn;
|
||||
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
qb_ipcs_connection_ref(c);
|
||||
|
||||
res = c->service->funcs.sendv(&c->event, iov, iov_len);
|
||||
if (res > 0) {
|
||||
c->stats.events++;
|
||||
resn = new_event_notification(c);
|
||||
if (resn < 0 && resn != -EAGAIN) {
|
||||
errno = -resn;
|
||||
qb_util_perror(LOG_WARNING, "new_event_notification");
|
||||
}
|
||||
}
|
||||
|
||||
qb_ipcs_connection_unref(c);
|
||||
return res;
|
||||
}
|
||||
|
||||
qb_ipcs_connection_t *
|
||||
qb_ipcs_connection_first_get(struct qb_ipcs_service * s)
|
||||
{
|
||||
struct qb_ipcs_connection *c;
|
||||
struct qb_list_head *iter;
|
||||
|
||||
if (qb_list_empty(&s->connections)) {
|
||||
return NULL;
|
||||
}
|
||||
iter = s->connections.next;
|
||||
|
||||
c = qb_list_entry(iter, struct qb_ipcs_connection, list);
|
||||
qb_ipcs_connection_ref(c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
qb_ipcs_connection_t *
|
||||
qb_ipcs_connection_next_get(struct qb_ipcs_service * s,
|
||||
struct qb_ipcs_connection * current)
|
||||
{
|
||||
struct qb_ipcs_connection *c;
|
||||
struct qb_list_head *iter;
|
||||
|
||||
if (current == NULL || current->list.next == &s->connections) {
|
||||
return NULL;
|
||||
}
|
||||
iter = current->list.next;
|
||||
|
||||
c = qb_list_entry(iter, struct qb_ipcs_connection, list);
|
||||
qb_ipcs_connection_ref(c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcs_service_id_get(struct qb_ipcs_connection * c)
|
||||
{
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return c->service->service_id;
|
||||
}
|
||||
|
||||
struct qb_ipcs_connection *
|
||||
qb_ipcs_connection_alloc(struct qb_ipcs_service *s)
|
||||
{
|
||||
struct qb_ipcs_connection *c =
|
||||
calloc(1, sizeof(struct qb_ipcs_connection));
|
||||
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c->refcount = 1;
|
||||
c->service = s;
|
||||
c->pid = 0;
|
||||
c->euid = -1;
|
||||
c->egid = -1;
|
||||
qb_list_init(&c->list);
|
||||
c->receive_buf = NULL;
|
||||
c->context = NULL;
|
||||
c->fc_enabled = QB_FALSE;
|
||||
c->state = QB_IPCS_CONNECTION_INACTIVE;
|
||||
c->poll_events = POLLIN | POLLPRI | POLLNVAL;
|
||||
|
||||
c->setup.type = s->type;
|
||||
c->request.type = s->type;
|
||||
c->response.type = s->type;
|
||||
c->event.type = s->type;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_connection_ref(struct qb_ipcs_connection *c)
|
||||
{
|
||||
if (c) {
|
||||
qb_atomic_int_inc(&c->refcount);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_connection_unref(struct qb_ipcs_connection *c)
|
||||
{
|
||||
int32_t free_it;
|
||||
|
||||
if (c == NULL) {
|
||||
return;
|
||||
}
|
||||
if (c->refcount < 1) {
|
||||
qb_util_log(LOG_ERR, "ref:%d state:%d fd:%d",
|
||||
c->refcount, c->state,
|
||||
c->setup.u.us.sock);
|
||||
assert(0);
|
||||
}
|
||||
free_it = qb_atomic_int_dec_and_test(&c->refcount);
|
||||
if (free_it) {
|
||||
qb_list_del(&c->list);
|
||||
if (c->service->serv_fns.connection_destroyed) {
|
||||
c->service->serv_fns.connection_destroyed(c);
|
||||
}
|
||||
c->service->funcs.disconnect(c);
|
||||
free(c->receive_buf);
|
||||
free(c);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_disconnect(struct qb_ipcs_connection *c)
|
||||
{
|
||||
int32_t res = 0;
|
||||
qb_loop_job_dispatch_fn rerun_job;
|
||||
|
||||
if (c == NULL) {
|
||||
return;
|
||||
}
|
||||
qb_util_log(LOG_DEBUG, "%s() state:%d", __func__, c->state);
|
||||
|
||||
if (c->state == QB_IPCS_CONNECTION_ACTIVE) {
|
||||
c->state = QB_IPCS_CONNECTION_INACTIVE;
|
||||
c->service->stats.closed_connections++;
|
||||
if (c->service->needs_sock_for_poll && c->setup.u.us.sock > 0) {
|
||||
(void)c->service->poll_fns.dispatch_del(c->setup.u.us.sock);
|
||||
qb_ipcc_us_sock_close(c->setup.u.us.sock);
|
||||
c->setup.u.us.sock = -1;
|
||||
qb_ipcs_connection_unref(c);
|
||||
}
|
||||
/* return early as it's an incomplete connection.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
if (c->state == QB_IPCS_CONNECTION_ESTABLISHED) {
|
||||
c->state = QB_IPCS_CONNECTION_SHUTTING_DOWN;
|
||||
c->service->stats.active_connections--;
|
||||
c->service->stats.closed_connections++;
|
||||
|
||||
if (c->service->needs_sock_for_poll && c->setup.u.us.sock > 0) {
|
||||
(void)c->service->poll_fns.dispatch_del(c->setup.u.us.sock);
|
||||
qb_ipcc_us_sock_close(c->setup.u.us.sock);
|
||||
c->setup.u.us.sock = -1;
|
||||
qb_ipcs_connection_unref(c);
|
||||
}
|
||||
}
|
||||
if (c->state == QB_IPCS_CONNECTION_SHUTTING_DOWN) {
|
||||
res = 0;
|
||||
if (c->service->serv_fns.connection_closed) {
|
||||
res = c->service->serv_fns.connection_closed(c);
|
||||
}
|
||||
if (res == 0) {
|
||||
qb_ipcs_connection_unref(c);
|
||||
} else {
|
||||
/* OK, so they want the connection_closed
|
||||
* function re-run */
|
||||
rerun_job =
|
||||
(qb_loop_job_dispatch_fn) qb_ipcs_disconnect;
|
||||
res = c->service->poll_fns.job_add(QB_LOOP_LOW,
|
||||
c,
|
||||
rerun_job);
|
||||
if (res != 0) {
|
||||
/* last ditch attempt to cleanup */
|
||||
qb_ipcs_connection_unref(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qb_ipcs_flowcontrol_set(struct qb_ipcs_connection *c, int32_t fc_enable)
|
||||
{
|
||||
if (c == NULL) {
|
||||
return;
|
||||
}
|
||||
if (c->fc_enabled != fc_enable) {
|
||||
c->service->funcs.fc_set(&c->request, fc_enable);
|
||||
c->fc_enabled = fc_enable;
|
||||
c->stats.flow_control_state = fc_enable;
|
||||
c->stats.flow_control_count++;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_process_request_(struct qb_ipcs_connection *c, int32_t ms_timeout)
|
||||
{
|
||||
int32_t res = 0;
|
||||
ssize_t size;
|
||||
struct qb_ipc_request_header *hdr;
|
||||
|
||||
qb_ipcs_connection_ref(c);
|
||||
|
||||
if (c->service->funcs.peek && c->service->funcs.reclaim) {
|
||||
size = c->service->funcs.peek(&c->request, (void **)&hdr,
|
||||
ms_timeout);
|
||||
} else {
|
||||
hdr = c->receive_buf;
|
||||
size = c->service->funcs.recv(&c->request,
|
||||
hdr,
|
||||
c->request.max_msg_size,
|
||||
ms_timeout);
|
||||
}
|
||||
if (size < 0) {
|
||||
if (size != -EAGAIN && size != -ETIMEDOUT) {
|
||||
qb_util_perror(LOG_ERR,
|
||||
"recv from client connection failed");
|
||||
} else {
|
||||
c->stats.recv_retries++;
|
||||
}
|
||||
res = size;
|
||||
goto cleanup;
|
||||
}
|
||||
c->stats.requests++;
|
||||
|
||||
if (hdr->id == QB_IPC_MSG_DISCONNECT) {
|
||||
qb_util_log(LOG_DEBUG, "client requesting a disconnect");
|
||||
qb_ipcs_disconnect(c);
|
||||
res = -ESHUTDOWN;
|
||||
} else {
|
||||
res = c->service->serv_fns.msg_process(c, hdr, hdr->size);
|
||||
/* 0 == good, negative == backoff */
|
||||
if (res < 0) {
|
||||
res = -ENOBUFS;
|
||||
} else {
|
||||
res = size;
|
||||
}
|
||||
}
|
||||
|
||||
if (c->service->funcs.peek && c->service->funcs.reclaim) {
|
||||
c->service->funcs.reclaim(&c->request);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
qb_ipcs_connection_unref(c);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define IPC_REQUEST_TIMEOUT 10
|
||||
#define MAX_RECV_MSGS 50
|
||||
|
||||
int32_t
|
||||
qb_ipcs_dispatch_service_request(int32_t fd, int32_t revents, void *data)
|
||||
{
|
||||
int32_t res = _process_request_((struct qb_ipcs_connection *)data,
|
||||
IPC_REQUEST_TIMEOUT);
|
||||
if (res > 0) {
|
||||
return 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
_request_q_len_get(struct qb_ipcs_connection *c)
|
||||
{
|
||||
ssize_t q_len;
|
||||
if (c->service->funcs.q_len_get) {
|
||||
q_len = c->service->funcs.q_len_get(&c->request);
|
||||
if (q_len <= 0) {
|
||||
return q_len;
|
||||
}
|
||||
if (c->service->poll_priority == QB_LOOP_MED) {
|
||||
q_len = QB_MIN(q_len, 5);
|
||||
} else if (c->service->poll_priority == QB_LOOP_LOW) {
|
||||
q_len = 1;
|
||||
} else {
|
||||
q_len = QB_MIN(q_len, MAX_RECV_MSGS);
|
||||
}
|
||||
} else {
|
||||
q_len = 1;
|
||||
}
|
||||
return q_len;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcs_dispatch_connection_request(int32_t fd, int32_t revents, void *data)
|
||||
{
|
||||
struct qb_ipcs_connection *c = (struct qb_ipcs_connection *)data;
|
||||
char bytes[MAX_RECV_MSGS];
|
||||
int32_t res;
|
||||
int32_t res2;
|
||||
int32_t recvd = 0;
|
||||
ssize_t avail;
|
||||
|
||||
if (revents & POLLHUP) {
|
||||
qb_util_log(LOG_DEBUG, "HUP conn:%p fd:%d", c, fd);
|
||||
qb_ipcs_disconnect(c);
|
||||
return -ESHUTDOWN;
|
||||
}
|
||||
|
||||
if (revents & POLLOUT) {
|
||||
res = resend_event_notifications(c);
|
||||
if (res < 0 && res != -EAGAIN) {
|
||||
errno = -res;
|
||||
qb_util_perror(LOG_WARNING, "resend_event_notifications");
|
||||
}
|
||||
if ((revents & POLLIN) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (c->fc_enabled) {
|
||||
return 0;
|
||||
}
|
||||
avail = _request_q_len_get(c);
|
||||
|
||||
if (c->service->needs_sock_for_poll && avail == 0) {
|
||||
res2 = qb_ipc_us_recv(&c->setup, bytes, 1, 0);
|
||||
qb_util_log(LOG_WARNING,
|
||||
"conn:%p Nothing in q but got POLLIN on fd:%d (res2:%d)",
|
||||
c, fd, res2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
res = _process_request_(c, IPC_REQUEST_TIMEOUT);
|
||||
if (res > 0 || res == -ENOBUFS || res == -EINVAL) {
|
||||
recvd++;
|
||||
}
|
||||
if (res > 0) {
|
||||
avail--;
|
||||
}
|
||||
} while (avail > 0 && res > 0 && !c->fc_enabled);
|
||||
|
||||
if (c->service->needs_sock_for_poll && recvd > 0) {
|
||||
res2 = qb_ipc_us_recv(&c->setup, bytes, recvd, -1);
|
||||
if (res2 < 0) {
|
||||
errno = -res2;
|
||||
qb_util_perror(LOG_ERR, "error receiving from setup sock");
|
||||
}
|
||||
}
|
||||
|
||||
res = QB_MIN(0, res);
|
||||
if (res == -EAGAIN || res == -ETIMEDOUT || res == -ENOBUFS) {
|
||||
res = 0;
|
||||
}
|
||||
if (res != 0) {
|
||||
errno = -res;
|
||||
qb_util_perror(LOG_ERR, "request returned error");
|
||||
qb_ipcs_connection_unref(c);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
qb_ipcs_context_set(struct qb_ipcs_connection *c, void *context)
|
||||
{
|
||||
if (c == NULL) {
|
||||
return;
|
||||
}
|
||||
c->context = context;
|
||||
}
|
||||
|
||||
void *
|
||||
qb_ipcs_context_get(struct qb_ipcs_connection *c)
|
||||
{
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return c->context;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcs_connection_stats_get(qb_ipcs_connection_t * c,
|
||||
struct qb_ipcs_connection_stats * stats,
|
||||
int32_t clear_after_read)
|
||||
{
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(stats, &c->stats, sizeof(struct qb_ipcs_connection_stats));
|
||||
if (clear_after_read) {
|
||||
memset(&c->stats, 0, sizeof(struct qb_ipcs_connection_stats));
|
||||
c->stats.client_pid = c->pid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_ipcs_stats_get(struct qb_ipcs_service * s,
|
||||
struct qb_ipcs_stats * stats, int32_t clear_after_read)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(stats, &s->stats, sizeof(struct qb_ipcs_stats));
|
||||
if (clear_after_read) {
|
||||
memset(&s->stats, 0, sizeof(struct qb_ipcs_stats));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
11
lib/libqb.pc.in
Normal file
11
lib/libqb.pc.in
Normal file
@ -0,0 +1,11 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=${prefix}
|
||||
libdir=@libdir@
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libqb
|
||||
Version: @PACKAGE_VERSION@
|
||||
Description: libqb
|
||||
Requires:
|
||||
Libs: -L${libdir} -lqb @LIB_RT@ -ldl
|
||||
Cflags: -I${includedir}
|
||||
207
lib/log_blackbox.c
Normal file
207
lib/log_blackbox.c
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include <qb/qbrb.h>
|
||||
#include "util_int.h"
|
||||
#include "log_int.h"
|
||||
|
||||
static void
|
||||
_blackbox_reload(int32_t target)
|
||||
{
|
||||
struct qb_log_target *t = qb_log_target_get(target);
|
||||
|
||||
if (t->instance == NULL) {
|
||||
return;
|
||||
}
|
||||
qb_rb_close(t->instance);
|
||||
t->instance = qb_rb_open(t->filename, t->size,
|
||||
QB_RB_FLAG_CREATE | QB_RB_FLAG_OVERWRITE, 0);
|
||||
}
|
||||
|
||||
/* <u32> file lineno
|
||||
* <u32> function name length
|
||||
* <string> function name
|
||||
* <u32> buffer length
|
||||
* <string> buffer
|
||||
*/
|
||||
static void
|
||||
_blackbox_vlogger(int32_t target,
|
||||
struct qb_log_callsite *cs, time_t timestamp, va_list ap)
|
||||
{
|
||||
size_t max_size;
|
||||
size_t actual_size;
|
||||
size_t fn_size;
|
||||
char *chunk;
|
||||
struct qb_log_target *t = qb_log_target_get(target);
|
||||
|
||||
if (t->instance == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
fn_size = strlen(cs->function) + 1;
|
||||
|
||||
actual_size = 2 * sizeof(uint32_t) + fn_size + sizeof(time_t);
|
||||
max_size = actual_size + QB_LOG_MAX_LEN;
|
||||
|
||||
chunk = qb_rb_chunk_alloc(t->instance, max_size);
|
||||
|
||||
/* line number */
|
||||
memcpy(chunk, &cs->lineno, sizeof(uint32_t));
|
||||
chunk += sizeof(uint32_t);
|
||||
|
||||
/* function name */
|
||||
memcpy(chunk, &fn_size, sizeof(uint32_t));
|
||||
chunk += sizeof(uint32_t);
|
||||
memcpy(chunk, cs->function, fn_size);
|
||||
chunk += fn_size;
|
||||
|
||||
/* timestamp */
|
||||
memcpy(chunk, ×tamp, sizeof(time_t));
|
||||
chunk += sizeof(time_t);
|
||||
|
||||
/* log message */
|
||||
actual_size += qb_vsprintf_serialize(chunk, cs->format, ap);
|
||||
|
||||
(void)qb_rb_chunk_commit(t->instance, actual_size);
|
||||
}
|
||||
|
||||
static void
|
||||
_blackbox_close(int32_t target)
|
||||
{
|
||||
struct qb_log_target *t = qb_log_target_get(target);
|
||||
|
||||
if (t->instance) {
|
||||
qb_rb_close(t->instance);
|
||||
t->instance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_log_blackbox_open(struct qb_log_target *t)
|
||||
{
|
||||
if (t->size < 1024) {
|
||||
return -EINVAL;
|
||||
}
|
||||
snprintf(t->filename, PATH_MAX, "%s-blackbox", t->name);
|
||||
|
||||
t->instance = qb_rb_open(t->filename, t->size,
|
||||
QB_RB_FLAG_CREATE | QB_RB_FLAG_OVERWRITE, 0);
|
||||
if (t->instance == NULL) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
t->logger = NULL;
|
||||
t->vlogger = _blackbox_vlogger;
|
||||
t->reload = _blackbox_reload;
|
||||
t->close = _blackbox_close;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_log_blackbox_write_to_file(const char *filename)
|
||||
{
|
||||
ssize_t written_size = 0;
|
||||
struct qb_log_target *t;
|
||||
int fd = open(filename, O_CREAT | O_RDWR, 0700);
|
||||
|
||||
if (fd < 0) {
|
||||
return -errno;
|
||||
}
|
||||
t = qb_log_target_get(QB_LOG_BLACKBOX);
|
||||
if (t->instance) {
|
||||
written_size = qb_rb_write_to_file(t->instance, fd);
|
||||
} else {
|
||||
written_size = -ENOENT;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return written_size;
|
||||
}
|
||||
|
||||
void
|
||||
qb_log_blackbox_print_from_file(const char *bb_filename)
|
||||
{
|
||||
qb_ringbuffer_t *instance;
|
||||
ssize_t bytes_read;
|
||||
char chunk[512];
|
||||
int fd;
|
||||
char time_buf[64];
|
||||
|
||||
fd = open(bb_filename, 0);
|
||||
if (fd < 0) {
|
||||
qb_util_perror(LOG_ERR, "qb_log_blackbox_print_from_file");
|
||||
return;
|
||||
}
|
||||
instance = qb_rb_create_from_file(fd, 0);
|
||||
close(fd);
|
||||
if (instance == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
char *ptr;
|
||||
uint32_t lineno;
|
||||
uint32_t fn_size;
|
||||
char *function;
|
||||
uint32_t len;
|
||||
time_t timestamp;
|
||||
char message[QB_LOG_MAX_LEN];
|
||||
|
||||
bytes_read = qb_rb_chunk_read(instance, chunk, 512, 0);
|
||||
ptr = chunk;
|
||||
if (bytes_read > 0) {
|
||||
struct tm *tm;
|
||||
/* lineno */
|
||||
memcpy(&lineno, ptr, sizeof(uint32_t));
|
||||
ptr += sizeof(uint32_t);
|
||||
|
||||
/* function size & name */
|
||||
memcpy(&fn_size, ptr, sizeof(uint32_t));
|
||||
ptr += sizeof(uint32_t);
|
||||
|
||||
function = ptr;
|
||||
ptr += fn_size;
|
||||
|
||||
/* timestamp size & content */
|
||||
memcpy(×tamp, ptr, sizeof(uint32_t));
|
||||
ptr += sizeof(time_t);
|
||||
tm = localtime(×tamp);
|
||||
if (tm) {
|
||||
(void)strftime(time_buf,
|
||||
sizeof(time_buf), "%b %d %T",
|
||||
tm);
|
||||
} else {
|
||||
snprintf(time_buf, sizeof(time_buf), "%ld",
|
||||
(long int)timestamp);
|
||||
}
|
||||
/* message content */
|
||||
len = qb_vsnprintf_deserialize(message, QB_LOG_MAX_LEN, ptr);
|
||||
len--;
|
||||
while (message[len] == '\n' || message[len] == '\0') {
|
||||
message[len] = '\0';
|
||||
len--;
|
||||
}
|
||||
printf("%s %s():%d %s\n",
|
||||
time_buf, function, lineno, message);
|
||||
}
|
||||
} while (bytes_read > 0);
|
||||
}
|
||||
202
lib/log_dcs.c
Normal file
202
lib/log_dcs.c
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
#include <ctype.h>
|
||||
#ifdef HAVE_LINK_H
|
||||
#include <link.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qblog.h>
|
||||
#include <qb/qbutil.h>
|
||||
#include <qb/qbarray.h>
|
||||
#include "log_int.h"
|
||||
|
||||
static qb_array_t *lookup_arr = NULL;
|
||||
static qb_array_t *callsite_arr = NULL;
|
||||
static uint32_t callsite_arr_next = 0;
|
||||
static uint32_t callsite_num_bins = 0;
|
||||
static uint32_t callsite_elems_per_bin = 0;
|
||||
static qb_thread_lock_t *arr_next_lock = NULL;
|
||||
|
||||
struct callsite_list {
|
||||
struct qb_log_callsite *cs;
|
||||
struct callsite_list *next;
|
||||
};
|
||||
|
||||
static void
|
||||
_log_register_callsites(void)
|
||||
{
|
||||
struct qb_log_callsite *start;
|
||||
struct qb_log_callsite *stop;
|
||||
int32_t b;
|
||||
int32_t rc;
|
||||
uint32_t num_bins = qb_array_num_bins_get(callsite_arr);
|
||||
|
||||
for (b = callsite_num_bins; b < num_bins; b++) {
|
||||
/* get the first element in the bin */
|
||||
rc = qb_array_index(callsite_arr,
|
||||
b * callsite_elems_per_bin,
|
||||
(void **)&start);
|
||||
if (rc == 0) {
|
||||
stop = &start[callsite_elems_per_bin];
|
||||
if (qb_log_callsites_register(start, stop) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
callsite_num_bins++;
|
||||
}
|
||||
}
|
||||
|
||||
static struct qb_log_callsite *
|
||||
_log_dcs_new_cs(const char *function,
|
||||
const char *filename,
|
||||
const char *format,
|
||||
uint8_t priority, uint32_t lineno, uint32_t tags)
|
||||
{
|
||||
struct qb_log_callsite *cs;
|
||||
int32_t rc;
|
||||
int32_t call_register = QB_FALSE;
|
||||
|
||||
if (qb_array_index(callsite_arr, callsite_arr_next, (void **)&cs) < 0) {
|
||||
rc = qb_array_grow(callsite_arr,
|
||||
callsite_arr_next + callsite_elems_per_bin / 2);
|
||||
assert(rc == 0);
|
||||
rc = qb_array_index(callsite_arr, callsite_arr_next,
|
||||
(void **)&cs);
|
||||
assert(rc == 0);
|
||||
assert(cs != NULL);
|
||||
call_register = QB_TRUE;
|
||||
}
|
||||
callsite_arr_next++;
|
||||
|
||||
cs->function = function;
|
||||
cs->filename = filename;
|
||||
cs->format = format;
|
||||
cs->priority = priority;
|
||||
cs->lineno = lineno;
|
||||
cs->tags = tags;
|
||||
|
||||
if (call_register) {
|
||||
_log_register_callsites();
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
struct qb_log_callsite *
|
||||
qb_log_dcs_get(int32_t * newly_created,
|
||||
const char *function,
|
||||
const char *filename,
|
||||
const char *format,
|
||||
uint8_t priority, uint32_t lineno, uint32_t tags)
|
||||
{
|
||||
int32_t rc;
|
||||
struct qb_log_callsite *cs = NULL;
|
||||
struct callsite_list *csl_head;
|
||||
struct callsite_list *csl_last;
|
||||
struct callsite_list *csl;
|
||||
const char *safe_filename = filename;
|
||||
const char *safe_function = function;
|
||||
|
||||
if (filename == NULL) {
|
||||
safe_filename = "";
|
||||
}
|
||||
if (function == NULL) {
|
||||
safe_function = "";
|
||||
}
|
||||
/*
|
||||
* try the fastest access first (no locking needed)
|
||||
*/
|
||||
rc = qb_array_index(lookup_arr, lineno, (void **)&csl_head);
|
||||
assert(rc == 0);
|
||||
if (csl_head->cs &&
|
||||
format == csl_head->cs->format &&
|
||||
priority == csl_head->cs->priority &&
|
||||
strcmp(safe_filename, csl_head->cs->filename) == 0) {
|
||||
return csl_head->cs;
|
||||
}
|
||||
/*
|
||||
* so we will either have to create it or go through a list, so lock it.
|
||||
*/
|
||||
(void)qb_thread_lock(arr_next_lock);
|
||||
if (csl_head->cs == NULL) {
|
||||
csl_head->cs = _log_dcs_new_cs(safe_function, safe_filename, format,
|
||||
priority, lineno, tags);
|
||||
cs = csl_head->cs;
|
||||
csl_head->next = NULL;
|
||||
*newly_created = QB_TRUE;
|
||||
} else {
|
||||
for (csl = csl_head; csl; csl = csl->next) {
|
||||
assert(csl->cs->lineno == lineno);
|
||||
if (format == csl->cs->format &&
|
||||
priority == csl->cs->priority &&
|
||||
strcmp(safe_filename, csl->cs->filename) == 0) {
|
||||
cs = csl->cs;
|
||||
break;
|
||||
}
|
||||
csl_last = csl;
|
||||
}
|
||||
|
||||
if (cs == NULL) {
|
||||
csl = calloc(1, sizeof(struct callsite_list));
|
||||
if (csl == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
csl->cs = _log_dcs_new_cs(safe_function, safe_filename, format,
|
||||
priority, lineno, tags);
|
||||
csl->next = NULL;
|
||||
csl_last->next = csl;
|
||||
cs = csl->cs;
|
||||
*newly_created = QB_TRUE;
|
||||
}
|
||||
}
|
||||
cleanup:
|
||||
(void)qb_thread_unlock(arr_next_lock);
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
void
|
||||
qb_log_dcs_init(void)
|
||||
{
|
||||
lookup_arr = qb_array_create_2(16, sizeof(struct callsite_list), 1);
|
||||
|
||||
/*
|
||||
* this needs to be a non-auto-growing array, as we want to know when
|
||||
* a new bin gets created so we can call qb_log_callsites_register().
|
||||
*/
|
||||
callsite_arr = qb_array_create(16, sizeof(struct qb_log_callsite));
|
||||
|
||||
arr_next_lock = qb_thread_lock_create(QB_THREAD_LOCK_SHORT);
|
||||
|
||||
callsite_elems_per_bin = qb_array_elems_per_bin_get(callsite_arr);
|
||||
_log_register_callsites();
|
||||
}
|
||||
|
||||
void
|
||||
qb_log_dcs_fini(void)
|
||||
{
|
||||
qb_array_free(lookup_arr);
|
||||
qb_array_free(callsite_arr);
|
||||
(void)qb_thread_lock_destroy(arr_next_lock);
|
||||
}
|
||||
111
lib/log_file.c
Normal file
111
lib/log_file.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
#include "log_int.h"
|
||||
|
||||
static void
|
||||
_file_logger(int32_t t,
|
||||
struct qb_log_callsite *cs, time_t timestamp, const char *msg)
|
||||
{
|
||||
char output_buffer[QB_LOG_MAX_LEN];
|
||||
FILE *f = qb_log_target_user_data_get(t);
|
||||
|
||||
if (f == NULL) {
|
||||
return;
|
||||
}
|
||||
output_buffer[0] = '\0';
|
||||
|
||||
qb_log_target_format(t, cs, timestamp, msg, output_buffer);
|
||||
|
||||
fprintf(f, "%s\n", output_buffer);
|
||||
fflush(f);
|
||||
}
|
||||
|
||||
static void
|
||||
_file_close(int32_t t)
|
||||
{
|
||||
FILE *f = qb_log_target_user_data_get(t);
|
||||
|
||||
if (f) {
|
||||
fclose(f);
|
||||
(void)qb_log_target_user_data_set(t, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_file_reload(int32_t target)
|
||||
{
|
||||
struct qb_log_target *t = qb_log_target_get(target);
|
||||
|
||||
if (t->instance) {
|
||||
fclose(t->instance);
|
||||
}
|
||||
t->instance = fopen(t->filename, "a+");
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_log_stderr_open(struct qb_log_target *t)
|
||||
{
|
||||
t->logger = _file_logger;
|
||||
t->reload = NULL;
|
||||
t->close = NULL;
|
||||
if (t->pos == QB_LOG_STDERR) {
|
||||
(void)strlcpy(t->filename, "stderr", PATH_MAX);
|
||||
t->instance = stderr;
|
||||
} else {
|
||||
(void)strlcpy(t->filename, "stdout", PATH_MAX);
|
||||
t->instance = stdout;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_log_file_open(const char *filename)
|
||||
{
|
||||
struct qb_log_target *t;
|
||||
FILE *fp;
|
||||
int32_t rc;
|
||||
|
||||
t = qb_log_target_alloc();
|
||||
if (t == NULL) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
fp = fopen(filename, "a+");
|
||||
if (fp == NULL) {
|
||||
rc = -errno;
|
||||
qb_log_target_free(t);
|
||||
return rc;
|
||||
}
|
||||
t->instance = fp;
|
||||
(void)strlcpy(t->filename, filename, PATH_MAX);
|
||||
|
||||
t->logger = _file_logger;
|
||||
t->reload = _file_reload;
|
||||
t->close = _file_close;
|
||||
return t->pos;
|
||||
}
|
||||
|
||||
void
|
||||
qb_log_file_close(int32_t t)
|
||||
{
|
||||
qb_log_custom_close(t);
|
||||
}
|
||||
702
lib/log_format.c
Normal file
702
lib/log_format.c
Normal file
@ -0,0 +1,702 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include "log_int.h"
|
||||
|
||||
static qb_log_tags_stringify_fn _user_tags_stringify_fn;
|
||||
|
||||
/*
|
||||
* syslog prioritynames, facility names to value mapping
|
||||
* Some C libraries build this in to their headers, but it is non-portable
|
||||
* so logsys supplies its own version.
|
||||
*/
|
||||
struct syslog_names {
|
||||
const char *c_name;
|
||||
int32_t c_val;
|
||||
};
|
||||
|
||||
static struct syslog_names prioritynames[] = {
|
||||
{"emerg", LOG_EMERG},
|
||||
{"alert", LOG_ALERT},
|
||||
{"crit", LOG_CRIT},
|
||||
{"error", LOG_ERR},
|
||||
{"warning", LOG_WARNING},
|
||||
{"notice", LOG_NOTICE},
|
||||
{"info", LOG_INFO},
|
||||
{"debug", LOG_DEBUG},
|
||||
{"trace", LOG_TRACE},
|
||||
{NULL, -1}
|
||||
};
|
||||
|
||||
struct syslog_names facilitynames[] = {
|
||||
{"auth", LOG_AUTH},
|
||||
{"authpriv", LOG_AUTHPRIV},
|
||||
{"cron", LOG_CRON},
|
||||
{"daemon", LOG_DAEMON},
|
||||
{"ftp", LOG_FTP},
|
||||
{"kern", LOG_KERN},
|
||||
{"lpr", LOG_LPR},
|
||||
{"mail", LOG_MAIL},
|
||||
{"news", LOG_NEWS},
|
||||
{"syslog", LOG_SYSLOG},
|
||||
{"user", LOG_USER},
|
||||
{"uucp", LOG_UUCP},
|
||||
{"local0", LOG_LOCAL0},
|
||||
{"local1", LOG_LOCAL1},
|
||||
{"local2", LOG_LOCAL2},
|
||||
{"local3", LOG_LOCAL3},
|
||||
{"local4", LOG_LOCAL4},
|
||||
{"local5", LOG_LOCAL5},
|
||||
{"local6", LOG_LOCAL6},
|
||||
{"local7", LOG_LOCAL7},
|
||||
{NULL, -1}
|
||||
};
|
||||
|
||||
static const char log_month_name[][4] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
/* Convert string "auth" to equivalent number "LOG_AUTH" etc. */
|
||||
int32_t
|
||||
qb_log_facility2int(const char *fname)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
if (fname == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; facilitynames[i].c_name != NULL; i++) {
|
||||
if (strcmp(fname, facilitynames[i].c_name) == 0) {
|
||||
return facilitynames[i].c_val;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Convert number "LOG_AUTH" to equivalent string "auth" etc. */
|
||||
const char *
|
||||
qb_log_facility2str(int32_t fnum)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
for (i = 0; facilitynames[i].c_name != NULL; i++) {
|
||||
if (facilitynames[i].c_val == fnum) {
|
||||
return facilitynames[i].c_name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
qb_log_tags_stringify_fn_set(qb_log_tags_stringify_fn fn)
|
||||
{
|
||||
_user_tags_stringify_fn = fn;
|
||||
}
|
||||
|
||||
static int
|
||||
_strcpy_cutoff(char *dest, const char *src, size_t cutoff, int ralign,
|
||||
size_t buf_len)
|
||||
{
|
||||
size_t len = strlen(src);
|
||||
if (buf_len <= 1) {
|
||||
if (buf_len == 0)
|
||||
dest[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cutoff == 0) {
|
||||
cutoff = len;
|
||||
}
|
||||
|
||||
cutoff = QB_MIN(cutoff, buf_len - 1);
|
||||
len = QB_MIN(len, cutoff);
|
||||
if (ralign) {
|
||||
memset(dest, ' ', cutoff - len);
|
||||
memcpy(dest + cutoff - len, src, len);
|
||||
} else {
|
||||
memcpy(dest, src, len);
|
||||
memset(dest + len, ' ', cutoff - len);
|
||||
}
|
||||
|
||||
dest[cutoff] = '\0';
|
||||
|
||||
return cutoff;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will do static formatting (for things that don't
|
||||
* change on each log message).
|
||||
*
|
||||
* %P PID
|
||||
* %N name passed into qb_log_init
|
||||
* %H hostname
|
||||
*
|
||||
* any number between % and character specify field length to pad or chop
|
||||
*/
|
||||
void
|
||||
qb_log_target_format_static(int32_t target, const char * format,
|
||||
char *output_buffer)
|
||||
{
|
||||
char tmp_buf[255];
|
||||
unsigned int format_buffer_idx = 0;
|
||||
unsigned int output_buffer_idx = 0;
|
||||
size_t cutoff;
|
||||
uint32_t len;
|
||||
int ralign;
|
||||
int c;
|
||||
struct qb_log_target *t = qb_log_target_get(target);
|
||||
|
||||
if (format == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((c = format[format_buffer_idx])) {
|
||||
cutoff = 0;
|
||||
ralign = 0;
|
||||
if (c != '%') {
|
||||
output_buffer[output_buffer_idx++] = c;
|
||||
format_buffer_idx++;
|
||||
} else {
|
||||
const char *p;
|
||||
unsigned int percent_buffer_idx = format_buffer_idx;
|
||||
|
||||
format_buffer_idx += 1;
|
||||
if (format[format_buffer_idx] == '-') {
|
||||
ralign = 1;
|
||||
format_buffer_idx += 1;
|
||||
}
|
||||
|
||||
if (isdigit(format[format_buffer_idx])) {
|
||||
cutoff = atoi(&format[format_buffer_idx]);
|
||||
}
|
||||
while (isdigit(format[format_buffer_idx])) {
|
||||
format_buffer_idx += 1;
|
||||
}
|
||||
|
||||
switch (format[format_buffer_idx]) {
|
||||
case 'P':
|
||||
snprintf(tmp_buf, 30, "%d", getpid());
|
||||
p = tmp_buf;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
p = t->name;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
if (gethostname(tmp_buf, 255) == 0) {
|
||||
tmp_buf[254] = '\0';
|
||||
} else {
|
||||
(void)strlcpy(tmp_buf, "localhost", 255);
|
||||
}
|
||||
p = tmp_buf;
|
||||
break;
|
||||
|
||||
default:
|
||||
p = &format[percent_buffer_idx];
|
||||
cutoff = (format_buffer_idx - percent_buffer_idx + 1);
|
||||
ralign = 0;
|
||||
break;
|
||||
}
|
||||
len = _strcpy_cutoff(output_buffer + output_buffer_idx,
|
||||
p, cutoff, ralign,
|
||||
(QB_LOG_MAX_LEN -
|
||||
output_buffer_idx));
|
||||
output_buffer_idx += len;
|
||||
format_buffer_idx += 1;
|
||||
}
|
||||
if (output_buffer_idx >= QB_LOG_MAX_LEN - 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
output_buffer[output_buffer_idx] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* %n FUNCTION NAME
|
||||
* %f FILENAME
|
||||
* %l FILELINE
|
||||
* %p PRIORITY
|
||||
* %t TIMESTAMP
|
||||
* %b BUFFER
|
||||
* %g SUBSYSTEM
|
||||
*
|
||||
* any number between % and character specify field length to pad or chop
|
||||
*/
|
||||
void
|
||||
qb_log_target_format(int32_t target,
|
||||
struct qb_log_callsite *cs,
|
||||
time_t current_time,
|
||||
const char *formatted_message, char *output_buffer)
|
||||
{
|
||||
char tmp_buf[128];
|
||||
struct tm tm_res;
|
||||
unsigned int format_buffer_idx = 0;
|
||||
unsigned int output_buffer_idx = 0;
|
||||
size_t cutoff;
|
||||
uint32_t len;
|
||||
int ralign;
|
||||
int c;
|
||||
struct qb_log_target *t = qb_log_target_get(target);
|
||||
|
||||
if (t->format == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((c = t->format[format_buffer_idx])) {
|
||||
cutoff = 0;
|
||||
ralign = 0;
|
||||
if (c != '%') {
|
||||
output_buffer[output_buffer_idx++] = c;
|
||||
format_buffer_idx++;
|
||||
} else {
|
||||
const char *p;
|
||||
|
||||
format_buffer_idx += 1;
|
||||
if (t->format[format_buffer_idx] == '-') {
|
||||
ralign = 1;
|
||||
format_buffer_idx += 1;
|
||||
}
|
||||
|
||||
if (isdigit(t->format[format_buffer_idx])) {
|
||||
cutoff = atoi(&t->format[format_buffer_idx]);
|
||||
}
|
||||
while (isdigit(t->format[format_buffer_idx])) {
|
||||
format_buffer_idx += 1;
|
||||
}
|
||||
|
||||
switch (t->format[format_buffer_idx]) {
|
||||
case 'g':
|
||||
if (_user_tags_stringify_fn) {
|
||||
p = _user_tags_stringify_fn(cs->tags);
|
||||
} else {
|
||||
p = "";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
p = cs->function;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
#ifdef BUILDING_IN_PLACE
|
||||
p = cs->filename;
|
||||
#else
|
||||
p = strrchr(cs->filename, '/');
|
||||
if (p == NULL) {
|
||||
p = cs->filename;
|
||||
} else {
|
||||
p++; /* move past the "/" */
|
||||
}
|
||||
#endif /* BUILDING_IN_PLACE */
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
snprintf(tmp_buf, 30, "%d", cs->lineno);
|
||||
p = tmp_buf;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
(void)localtime_r(¤t_time, &tm_res);
|
||||
snprintf(tmp_buf, TIME_STRING_SIZE,
|
||||
"%s %02d %02d:%02d:%02d",
|
||||
log_month_name[tm_res.tm_mon],
|
||||
tm_res.tm_mday, tm_res.tm_hour,
|
||||
tm_res.tm_min, tm_res.tm_sec);
|
||||
p = tmp_buf;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
p = formatted_message;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if (cs->priority > LOG_TRACE) {
|
||||
p = prioritynames[LOG_TRACE].c_name;
|
||||
} else {
|
||||
p = prioritynames[cs->priority].c_name;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
p = "";
|
||||
break;
|
||||
}
|
||||
len = _strcpy_cutoff(output_buffer + output_buffer_idx,
|
||||
p, cutoff, ralign,
|
||||
(QB_LOG_MAX_LEN -
|
||||
output_buffer_idx));
|
||||
output_buffer_idx += len;
|
||||
format_buffer_idx += 1;
|
||||
}
|
||||
if (output_buffer_idx >= QB_LOG_MAX_LEN - 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (output_buffer[output_buffer_idx - 1] == '\n') {
|
||||
output_buffer[output_buffer_idx - 1] = '\0';
|
||||
} else {
|
||||
output_buffer[output_buffer_idx] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
qb_vsprintf_serialize(char *serialize, const char *fmt, va_list ap)
|
||||
{
|
||||
char *format;
|
||||
char *p;
|
||||
uint32_t location = 0;
|
||||
int type_long = 0;
|
||||
int type_longlong = 0;
|
||||
|
||||
p = stpcpy(serialize, fmt);
|
||||
location = p - serialize + 1;
|
||||
|
||||
format = (char *)fmt;
|
||||
for (;;) {
|
||||
type_long = 0;
|
||||
type_longlong = 0;
|
||||
p = strchrnul((const char *)format, '%');
|
||||
if (*p == '\0') {
|
||||
break;
|
||||
}
|
||||
format = p + 1;
|
||||
reprocess:
|
||||
switch (format[0]) {
|
||||
case '#': /* alternate form conversion, ignore */
|
||||
case '-': /* left adjust, ignore */
|
||||
case ' ': /* a space, ignore */
|
||||
case '+': /* a sign should be used, ignore */
|
||||
case '\'': /* group in thousands, ignore */
|
||||
case 'I': /* glibc-ism locale alternative, ignore */
|
||||
case '.': /* precision, ignore */
|
||||
case '0': /* field width, ignore */
|
||||
case '1': /* field width, ignore */
|
||||
case '2': /* field width, ignore */
|
||||
case '3': /* field width, ignore */
|
||||
case '4': /* field width, ignore */
|
||||
case '5': /* field width, ignore */
|
||||
case '6': /* field width, ignore */
|
||||
case '7': /* field width, ignore */
|
||||
case '8': /* field width, ignore */
|
||||
case '9': /* field width, ignore */
|
||||
format++;
|
||||
goto reprocess;
|
||||
|
||||
case '*': /* variable field width, save */ {
|
||||
int arg_int = va_arg(ap, int);
|
||||
memcpy(&serialize[location], &arg_int, sizeof (int));
|
||||
location += sizeof(int);
|
||||
format++;
|
||||
goto reprocess;
|
||||
}
|
||||
case 'l':
|
||||
format++;
|
||||
type_long = 1;
|
||||
if (*format == 'l') {
|
||||
type_long = 0;
|
||||
type_longlong = 1;
|
||||
format++;
|
||||
}
|
||||
goto reprocess;
|
||||
case 'd': /* int argument */
|
||||
case 'i': /* int argument */
|
||||
case 'o': /* unsigned int argument */
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (type_long) {
|
||||
long int arg_int;
|
||||
|
||||
arg_int = va_arg(ap, long int);
|
||||
memcpy(&serialize[location], &arg_int,
|
||||
sizeof(long int));
|
||||
location += sizeof(long int);
|
||||
format++;
|
||||
break;
|
||||
} else if (type_longlong) {
|
||||
long long int arg_int;
|
||||
|
||||
arg_int = va_arg(ap, long long int);
|
||||
memcpy(&serialize[location], &arg_int,
|
||||
sizeof(long long int));
|
||||
location += sizeof(long long int);
|
||||
format++;
|
||||
break;
|
||||
} else {
|
||||
int arg_int;
|
||||
|
||||
arg_int = va_arg(ap, int);
|
||||
memcpy(&serialize[location], &arg_int,
|
||||
sizeof(int));
|
||||
location += sizeof(int);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'a':
|
||||
case 'A':
|
||||
{
|
||||
double arg_double;
|
||||
|
||||
arg_double = va_arg(ap, double);
|
||||
memcpy (&serialize[location], &arg_double, sizeof (double));
|
||||
location += sizeof(double);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
{
|
||||
int arg_int;
|
||||
unsigned char arg_char;
|
||||
|
||||
arg_int = va_arg(ap, unsigned int);
|
||||
arg_char = (unsigned char)arg_int;
|
||||
memcpy (&serialize[location], &arg_char, sizeof (unsigned char));
|
||||
location += sizeof(unsigned char);
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
{
|
||||
char *arg_string;
|
||||
arg_string = va_arg(ap, char *);
|
||||
p = stpcpy(&serialize[location], arg_string);
|
||||
location += p - &serialize[location] + 1;
|
||||
break;
|
||||
}
|
||||
case 'p':
|
||||
{
|
||||
void *arg_pointer;
|
||||
arg_pointer = va_arg(ap, void *);
|
||||
memcpy (&serialize[location], &arg_pointer, sizeof (void *));
|
||||
location += sizeof (arg_pointer);
|
||||
break;
|
||||
}
|
||||
case '%':
|
||||
serialize[location++] = '%';
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return (location);
|
||||
}
|
||||
|
||||
#define MINI_FORMAT_STR_LEN 20
|
||||
|
||||
size_t
|
||||
qb_vsnprintf_deserialize(char *string, size_t str_len, const char *buf)
|
||||
{
|
||||
char *p;
|
||||
char *format;
|
||||
char fmt[MINI_FORMAT_STR_LEN];
|
||||
int fmt_pos;
|
||||
|
||||
uint32_t location = 0;
|
||||
uint32_t data_pos = strlen(buf) + 1;
|
||||
int type_long = 0;
|
||||
int type_longlong = 0;
|
||||
int len;
|
||||
|
||||
format = (char *)buf;
|
||||
for (;;) {
|
||||
type_long = 0;
|
||||
type_longlong = 0;
|
||||
p = strchrnul((const char *)format, '%');
|
||||
if (*p == '\0') {
|
||||
p = stpcpy(&string[location], format);
|
||||
location += p - &string[location] + 1;
|
||||
break;
|
||||
}
|
||||
/* copy from current to the next % */
|
||||
len = p - format;
|
||||
strncpy(&string[location], format, len);
|
||||
location += len;
|
||||
format = p;
|
||||
|
||||
/* start building up the format for snprintf */
|
||||
fmt_pos = 0;
|
||||
fmt[fmt_pos++] = *format;
|
||||
format++;
|
||||
reprocess:
|
||||
switch (format[0]) {
|
||||
case '#': /* alternate form conversion, ignore */
|
||||
case '-': /* left adjust, ignore */
|
||||
case ' ': /* a space, ignore */
|
||||
case '+': /* a sign should be used, ignore */
|
||||
case '\'': /* group in thousands, ignore */
|
||||
case 'I': /* glibc-ism locale alternative, ignore */
|
||||
case '.': /* precision, ignore */
|
||||
case '0': /* field width, ignore */
|
||||
case '1': /* field width, ignore */
|
||||
case '2': /* field width, ignore */
|
||||
case '3': /* field width, ignore */
|
||||
case '4': /* field width, ignore */
|
||||
case '5': /* field width, ignore */
|
||||
case '6': /* field width, ignore */
|
||||
case '7': /* field width, ignore */
|
||||
case '8': /* field width, ignore */
|
||||
case '9': /* field width, ignore */
|
||||
fmt[fmt_pos++] = *format;
|
||||
format++;
|
||||
goto reprocess;
|
||||
|
||||
case '*': {
|
||||
int arg_int;
|
||||
memcpy(&arg_int, &buf[data_pos], sizeof(int));
|
||||
data_pos += sizeof(int);
|
||||
fmt_pos += snprintf(&fmt[fmt_pos],
|
||||
MINI_FORMAT_STR_LEN - fmt_pos,
|
||||
"%d", arg_int);
|
||||
format++;
|
||||
goto reprocess;
|
||||
}
|
||||
case 'l':
|
||||
fmt[fmt_pos++] = *format;
|
||||
format++;
|
||||
type_long = 1;
|
||||
if (*format == 'l') {
|
||||
type_long = 0;
|
||||
type_longlong = 1;
|
||||
}
|
||||
goto reprocess;
|
||||
case 'd': /* int argument */
|
||||
case 'i': /* int argument */
|
||||
case 'o': /* unsigned int argument */
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (type_long) {
|
||||
long int arg_int;
|
||||
|
||||
fmt[fmt_pos++] = *format;
|
||||
fmt[fmt_pos++] = '\0';
|
||||
memcpy(&arg_int, &buf[data_pos], sizeof(long int));
|
||||
location += snprintf(&string[location],
|
||||
str_len - location,
|
||||
fmt, arg_int);
|
||||
data_pos += sizeof(long int);
|
||||
format++;
|
||||
break;
|
||||
} else if (type_longlong) {
|
||||
long long int arg_int;
|
||||
|
||||
fmt[fmt_pos++] = *format;
|
||||
fmt[fmt_pos++] = '\0';
|
||||
memcpy(&arg_int, &buf[data_pos], sizeof(long long int));
|
||||
location += snprintf(&string[location],
|
||||
str_len - location,
|
||||
fmt, arg_int);
|
||||
data_pos += sizeof(long long int);
|
||||
format++;
|
||||
break;
|
||||
} else {
|
||||
int arg_int;
|
||||
|
||||
fmt[fmt_pos++] = *format;
|
||||
fmt[fmt_pos++] = '\0';
|
||||
memcpy(&arg_int, &buf[data_pos], sizeof(int));
|
||||
location += snprintf(&string[location],
|
||||
str_len - location,
|
||||
fmt, arg_int);
|
||||
data_pos += sizeof(int);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'a':
|
||||
case 'A':
|
||||
{
|
||||
double arg_double;
|
||||
|
||||
fmt[fmt_pos++] = *format;
|
||||
fmt[fmt_pos++] = '\0';
|
||||
memcpy(&arg_double, &buf[data_pos], sizeof(double));
|
||||
location += snprintf(&string[location],
|
||||
str_len - location,
|
||||
fmt, arg_double);
|
||||
data_pos += sizeof(double);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
{
|
||||
unsigned char *arg_char;
|
||||
|
||||
fmt[fmt_pos++] = *format;
|
||||
fmt[fmt_pos++] = '\0';
|
||||
arg_char = (unsigned char*)&buf[data_pos];
|
||||
location += snprintf(&string[location],
|
||||
str_len - location,
|
||||
fmt, *arg_char);
|
||||
data_pos += sizeof(unsigned char);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
{
|
||||
fmt[fmt_pos++] = *format;
|
||||
fmt[fmt_pos++] = '\0';
|
||||
len = snprintf(&string[location],
|
||||
str_len - location,
|
||||
fmt, &buf[data_pos]);
|
||||
location += len;
|
||||
data_pos += len + 1;
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
case 'p':
|
||||
{
|
||||
fmt[fmt_pos++] = *format;
|
||||
fmt[fmt_pos++] = '\0';
|
||||
location = snprintf(&string[location],
|
||||
str_len - location,
|
||||
fmt, &buf[data_pos]);
|
||||
data_pos += sizeof(void*);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
case '%':
|
||||
string[location++] = '%';
|
||||
format++;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
102
lib/log_int.h
Normal file
102
lib/log_int.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _QB_LOG_INT_H_
|
||||
#define _QB_LOG_INT_H_
|
||||
|
||||
#include <qb/qblist.h>
|
||||
#include <qb/qblog.h>
|
||||
#include <qb/qbrb.h>
|
||||
|
||||
struct qb_log_target;
|
||||
|
||||
struct qb_log_target {
|
||||
uint32_t pos;
|
||||
enum qb_log_target_state state;
|
||||
char name[PATH_MAX];
|
||||
char filename[PATH_MAX];
|
||||
struct qb_list_head filter_head;
|
||||
int32_t facility;
|
||||
int32_t priority_bump;
|
||||
int32_t debug;
|
||||
size_t size;
|
||||
char *format;
|
||||
int32_t threaded;
|
||||
void *instance;
|
||||
|
||||
qb_log_reload_fn reload;
|
||||
qb_log_close_fn close;
|
||||
qb_log_logger_fn logger;
|
||||
qb_log_vlogger_fn vlogger;
|
||||
};
|
||||
|
||||
struct qb_log_filter {
|
||||
enum qb_log_filter_conf conf;
|
||||
enum qb_log_filter_type type;
|
||||
char *text;
|
||||
uint8_t high_priority;
|
||||
uint8_t low_priority;
|
||||
uint32_t new_value;
|
||||
struct qb_list_head list;
|
||||
};
|
||||
|
||||
struct qb_log_record {
|
||||
struct qb_log_callsite *cs;
|
||||
time_t timestamp;
|
||||
char *buffer;
|
||||
struct qb_list_head list;
|
||||
};
|
||||
|
||||
|
||||
#define TIME_STRING_SIZE 64
|
||||
|
||||
struct qb_log_target * qb_log_target_alloc(void);
|
||||
void qb_log_target_free(struct qb_log_target *t);
|
||||
struct qb_log_target * qb_log_target_get(int32_t pos);
|
||||
|
||||
int32_t qb_log_syslog_open(struct qb_log_target *t);
|
||||
int32_t qb_log_stderr_open(struct qb_log_target *t);
|
||||
int32_t qb_log_blackbox_open(struct qb_log_target *t);
|
||||
|
||||
void qb_log_thread_stop(void);
|
||||
void qb_log_thread_log_post(struct qb_log_callsite *cs,
|
||||
time_t current_time,
|
||||
const char *buffer);
|
||||
void qb_log_thread_log_write(struct qb_log_callsite *cs,
|
||||
time_t current_time,
|
||||
const char *buffer);
|
||||
|
||||
void qb_log_dcs_init(void);
|
||||
void qb_log_dcs_fini(void);
|
||||
struct qb_log_callsite *qb_log_dcs_get(int32_t *newly_created,
|
||||
const char *function,
|
||||
const char *filename,
|
||||
const char *format,
|
||||
uint8_t priority,
|
||||
uint32_t lineno,
|
||||
uint32_t tags);
|
||||
|
||||
size_t qb_vsprintf_serialize(char *serialize, const char *fmt, va_list ap);
|
||||
size_t qb_vsnprintf_deserialize(char *string, size_t str_len, const char *buf);
|
||||
|
||||
void qb_log_target_format_static(int32_t target, const char * format, char *output_buffer);
|
||||
|
||||
#endif /* _QB_LOG_INT_H_ */
|
||||
|
||||
78
lib/log_syslog.c
Normal file
78
lib/log_syslog.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
#include <syslog.h>
|
||||
#endif /* HAVE_SYSLOG_H */
|
||||
#include "log_int.h"
|
||||
|
||||
static void
|
||||
_syslog_logger(int32_t target,
|
||||
struct qb_log_callsite *cs, time_t timestamp, const char *msg)
|
||||
{
|
||||
char output_buffer[QB_LOG_MAX_LEN];
|
||||
struct qb_log_target *t = qb_log_target_get(target);
|
||||
int32_t final_priority = cs->priority;
|
||||
|
||||
if (final_priority > LOG_INFO) {
|
||||
/*
|
||||
* only bump the priority if it is greater than info.
|
||||
*/
|
||||
final_priority += t->priority_bump;
|
||||
}
|
||||
if (final_priority > LOG_DEBUG) {
|
||||
return;
|
||||
}
|
||||
|
||||
output_buffer[0] = '\0';
|
||||
qb_log_target_format(target, cs, timestamp, msg, output_buffer);
|
||||
|
||||
if (final_priority < LOG_EMERG) {
|
||||
final_priority = LOG_EMERG;
|
||||
}
|
||||
syslog(final_priority, "%s", output_buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
_syslog_close(int32_t target)
|
||||
{
|
||||
closelog();
|
||||
}
|
||||
|
||||
static void
|
||||
_syslog_reload(int32_t target)
|
||||
{
|
||||
struct qb_log_target *t = qb_log_target_get(target);
|
||||
closelog();
|
||||
openlog(t->name, LOG_PID, t->facility);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_log_syslog_open(struct qb_log_target *t)
|
||||
{
|
||||
t->logger = _syslog_logger;
|
||||
t->reload = _syslog_reload;
|
||||
t->close = _syslog_close;
|
||||
|
||||
openlog(t->name, LOG_PID, t->facility);
|
||||
return 0;
|
||||
}
|
||||
273
lib/log_thread.c
Normal file
273
lib/log_thread.c
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qblist.h>
|
||||
#include <qb/qbutil.h>
|
||||
#include "log_int.h"
|
||||
|
||||
static int wthread_active = 0;
|
||||
|
||||
static int wthread_should_exit = 0;
|
||||
|
||||
static qb_thread_lock_t *logt_wthread_lock = NULL;
|
||||
|
||||
static QB_LIST_DECLARE(logt_print_finished_records);
|
||||
|
||||
static int logt_memory_used = 0;
|
||||
|
||||
static int logt_dropped_messages = 0;
|
||||
|
||||
static sem_t logt_thread_start;
|
||||
|
||||
static sem_t logt_print_finished;
|
||||
|
||||
static int logt_sched_param_queued = QB_FALSE;
|
||||
|
||||
static int logt_sched_policy;
|
||||
|
||||
#if defined(HAVE_PTHREAD_SETSCHEDPARAM) && defined(HAVE_SCHED_GET_PRIORITY_MAX)
|
||||
static struct sched_param logt_sched_param;
|
||||
#endif /* HAVE_PTHREAD_SETSCHEDPARAM && HAVE_SCHED_GET_PRIORITY_MAX */
|
||||
|
||||
static pthread_t logt_thread_id = 0;
|
||||
|
||||
static void *qb_logt_worker_thread(void *data) __attribute__ ((noreturn));
|
||||
static void *
|
||||
qb_logt_worker_thread(void *data)
|
||||
{
|
||||
struct qb_log_record *rec;
|
||||
int dropped = 0;
|
||||
int res;
|
||||
|
||||
/*
|
||||
* Signal wthread_create that the initialization process may continue
|
||||
*/
|
||||
sem_post(&logt_thread_start);
|
||||
for (;;) {
|
||||
retry_sem_wait:
|
||||
res = sem_wait(&logt_print_finished);
|
||||
if (res == -1 && errno == EINTR) {
|
||||
goto retry_sem_wait;
|
||||
} else if (res == -1) {
|
||||
/*
|
||||
* This case shouldn't happen
|
||||
*/
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
(void)qb_thread_lock(logt_wthread_lock);
|
||||
if (wthread_should_exit) {
|
||||
int value = -1;
|
||||
|
||||
(void)sem_getvalue(&logt_print_finished, &value);
|
||||
if (value == 0) {
|
||||
(void)qb_thread_unlock(logt_wthread_lock);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
rec =
|
||||
qb_list_entry(logt_print_finished_records.next,
|
||||
struct qb_log_record, list);
|
||||
qb_list_del(&rec->list);
|
||||
logt_memory_used = logt_memory_used - strlen(rec->buffer) -
|
||||
sizeof(struct qb_log_record) - 1;
|
||||
dropped = logt_dropped_messages;
|
||||
logt_dropped_messages = 0;
|
||||
(void)qb_thread_unlock(logt_wthread_lock);
|
||||
if (dropped) {
|
||||
printf("%d messages lost\n", dropped);
|
||||
}
|
||||
|
||||
qb_log_thread_log_write(rec->cs, rec->timestamp, rec->buffer);
|
||||
free(rec->buffer);
|
||||
free(rec);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_log_thread_priority_set(int32_t policy, int32_t priority)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
#if defined(HAVE_PTHREAD_SETSCHEDPARAM) && defined(HAVE_SCHED_GET_PRIORITY_MAX)
|
||||
|
||||
logt_sched_policy = policy;
|
||||
|
||||
if (policy == SCHED_OTHER
|
||||
#ifdef SCHED_IDLE
|
||||
|| policy == SCHED_IDLE
|
||||
#endif
|
||||
#ifndef QB_DARWIN
|
||||
|| policy == SCHED_BATCH
|
||||
#endif
|
||||
) {
|
||||
logt_sched_param.sched_priority = 0;
|
||||
} else {
|
||||
logt_sched_param.sched_priority = priority;
|
||||
}
|
||||
if (wthread_active == 0) {
|
||||
logt_sched_param_queued = QB_TRUE;
|
||||
} else {
|
||||
res = pthread_setschedparam(logt_thread_id, policy,
|
||||
&logt_sched_param);
|
||||
if (res != 0) {
|
||||
res = -errno;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_log_thread_start(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (wthread_active) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
wthread_active = 1;
|
||||
res = pthread_create(&logt_thread_id, NULL,
|
||||
qb_logt_worker_thread, NULL);
|
||||
if (res != 0) {
|
||||
wthread_active = 0;
|
||||
return -errno;
|
||||
}
|
||||
sem_wait(&logt_thread_start);
|
||||
|
||||
if (logt_sched_param_queued) {
|
||||
res = qb_log_thread_priority_set(logt_sched_policy,
|
||||
logt_sched_param.sched_priority);
|
||||
if (res != 0) {
|
||||
goto cleanup_pthread;
|
||||
}
|
||||
logt_sched_param_queued = QB_FALSE;
|
||||
}
|
||||
logt_wthread_lock = qb_thread_lock_create(QB_THREAD_LOCK_SHORT);
|
||||
if (logt_wthread_lock == NULL) {
|
||||
goto cleanup_pthread;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_pthread:
|
||||
wthread_should_exit = 1;
|
||||
sem_post(&logt_print_finished);
|
||||
pthread_join(logt_thread_id, NULL);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
qb_log_thread_log_post(struct qb_log_callsite *cs,
|
||||
time_t timestamp, const char *buffer)
|
||||
{
|
||||
struct qb_log_record *rec;
|
||||
size_t buf_size;
|
||||
size_t total_size;
|
||||
|
||||
rec = malloc(sizeof(struct qb_log_record));
|
||||
if (rec == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
buf_size = strlen(buffer) + 1;
|
||||
total_size = sizeof(struct qb_log_record) + buf_size;
|
||||
|
||||
rec->cs = cs;
|
||||
rec->buffer = malloc(buf_size);
|
||||
if (rec->buffer == NULL) {
|
||||
goto free_record;
|
||||
}
|
||||
memcpy(rec->buffer, buffer, buf_size);
|
||||
|
||||
rec->timestamp = timestamp;
|
||||
|
||||
qb_list_init(&rec->list);
|
||||
(void)qb_thread_lock(logt_wthread_lock);
|
||||
logt_memory_used += total_size;
|
||||
if (logt_memory_used > 512000) {
|
||||
free(rec->buffer);
|
||||
free(rec);
|
||||
logt_memory_used = logt_memory_used - total_size;
|
||||
logt_dropped_messages += 1;
|
||||
(void)qb_thread_unlock(logt_wthread_lock);
|
||||
return;
|
||||
|
||||
} else {
|
||||
qb_list_add_tail(&rec->list, &logt_print_finished_records);
|
||||
}
|
||||
(void)qb_thread_unlock(logt_wthread_lock);
|
||||
|
||||
sem_post(&logt_print_finished);
|
||||
return;
|
||||
|
||||
free_record:
|
||||
free(rec);
|
||||
}
|
||||
|
||||
void
|
||||
qb_log_thread_stop(void)
|
||||
{
|
||||
int res;
|
||||
int value;
|
||||
struct qb_log_record *rec;
|
||||
|
||||
if (wthread_active == 0 && logt_wthread_lock == NULL) {
|
||||
return;
|
||||
}
|
||||
if (wthread_active == 0) {
|
||||
for (;;) {
|
||||
res = sem_getvalue(&logt_print_finished, &value);
|
||||
if (res != 0 || value == 0) {
|
||||
return;
|
||||
}
|
||||
sem_wait(&logt_print_finished);
|
||||
|
||||
(void)qb_thread_lock(logt_wthread_lock);
|
||||
|
||||
rec = qb_list_entry(logt_print_finished_records.next,
|
||||
struct qb_log_record, list);
|
||||
qb_list_del(&rec->list);
|
||||
logt_memory_used = logt_memory_used -
|
||||
strlen(rec->buffer) -
|
||||
sizeof(struct qb_log_record) - 1;
|
||||
(void)qb_thread_unlock(logt_wthread_lock);
|
||||
|
||||
qb_log_thread_log_write(rec->cs, rec->timestamp,
|
||||
rec->buffer);
|
||||
free(rec->buffer);
|
||||
free(rec);
|
||||
}
|
||||
} else {
|
||||
wthread_should_exit = 1;
|
||||
sem_post(&logt_print_finished);
|
||||
pthread_join(logt_thread_id, NULL);
|
||||
}
|
||||
(void)qb_thread_lock_destroy(logt_wthread_lock);
|
||||
}
|
||||
214
lib/loop.c
Normal file
214
lib/loop.c
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qblist.h>
|
||||
#include <qb/qbloop.h>
|
||||
#include "loop_int.h"
|
||||
#include "util_int.h"
|
||||
|
||||
static struct qb_loop *default_intance = NULL;
|
||||
|
||||
static void
|
||||
qb_loop_run_level(struct qb_loop_level *level)
|
||||
{
|
||||
struct qb_loop_item *job;
|
||||
struct qb_list_head *iter;
|
||||
int32_t processed = 0;
|
||||
|
||||
Ill_have_another:
|
||||
|
||||
iter = level->job_head.next;
|
||||
if (iter != &level->job_head) {
|
||||
job = qb_list_entry(iter, struct qb_loop_item, list);
|
||||
qb_list_del(&job->list);
|
||||
qb_list_init(&job->list);
|
||||
job->source->dispatch_and_take_back(job, level->priority);
|
||||
level->todo--;
|
||||
processed++;
|
||||
if (level->l->stop_requested) {
|
||||
return;
|
||||
}
|
||||
if (processed < level->to_process) {
|
||||
goto Ill_have_another;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qb_loop_level_item_add(struct qb_loop_level *level, struct qb_loop_item *job)
|
||||
{
|
||||
qb_list_init(&job->list);
|
||||
qb_list_add_tail(&job->list, &level->job_head);
|
||||
level->todo++;
|
||||
}
|
||||
|
||||
void
|
||||
qb_loop_level_item_del(struct qb_loop_level *level, struct qb_loop_item *job)
|
||||
{
|
||||
qb_list_del(&job->list);
|
||||
qb_list_init(&job->list);
|
||||
level->todo--;
|
||||
}
|
||||
|
||||
struct qb_loop *
|
||||
qb_loop_default_get(void)
|
||||
{
|
||||
return default_intance;
|
||||
}
|
||||
|
||||
struct qb_loop *
|
||||
qb_loop_create(void)
|
||||
{
|
||||
struct qb_loop *l = malloc(sizeof(struct qb_loop));
|
||||
int32_t p;
|
||||
|
||||
if (l == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
for (p = QB_LOOP_LOW; p <= QB_LOOP_HIGH; p++) {
|
||||
l->level[p].priority = p;
|
||||
l->level[p].to_process = 4;
|
||||
l->level[p].todo = 0;
|
||||
l->level[p].l = l;
|
||||
|
||||
qb_list_init(&l->level[p].job_head);
|
||||
qb_list_init(&l->level[p].wait_head);
|
||||
}
|
||||
|
||||
l->stop_requested = QB_FALSE;
|
||||
l->timer_source = qb_loop_timer_create(l);
|
||||
l->job_source = qb_loop_jobs_create(l);
|
||||
l->fd_source = qb_loop_poll_create(l);
|
||||
l->signal_source = qb_loop_signals_create(l);
|
||||
|
||||
if (default_intance == NULL) {
|
||||
default_intance = l;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
void
|
||||
qb_loop_destroy(struct qb_loop *l)
|
||||
{
|
||||
qb_loop_timer_destroy(l);
|
||||
qb_loop_jobs_destroy(l);
|
||||
qb_loop_poll_destroy(l);
|
||||
qb_loop_signals_destroy(l);
|
||||
|
||||
if (default_intance == l) {
|
||||
default_intance = NULL;
|
||||
}
|
||||
free(l);
|
||||
}
|
||||
|
||||
void
|
||||
qb_loop_stop(struct qb_loop *l)
|
||||
{
|
||||
if (l == NULL) {
|
||||
default_intance->stop_requested = QB_TRUE;
|
||||
} else {
|
||||
l->stop_requested = QB_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qb_loop_run(struct qb_loop *lp)
|
||||
{
|
||||
int32_t p;
|
||||
int32_t p_stop = QB_LOOP_LOW;
|
||||
int32_t rc;
|
||||
int32_t remaining_todo = 0;
|
||||
int32_t job_todo;
|
||||
int32_t timer_todo;
|
||||
int32_t ms_timeout;
|
||||
struct qb_loop *l = lp;
|
||||
|
||||
if (l == NULL) {
|
||||
l = default_intance;
|
||||
}
|
||||
l->stop_requested = QB_FALSE;
|
||||
|
||||
do {
|
||||
if (p_stop == QB_LOOP_LOW) {
|
||||
p_stop = QB_LOOP_HIGH;
|
||||
} else {
|
||||
p_stop--;
|
||||
}
|
||||
|
||||
job_todo = 0;
|
||||
if (l->job_source && l->job_source->poll) {
|
||||
rc = l->job_source->poll(l->job_source, 0);
|
||||
if (rc > 0) {
|
||||
job_todo = rc;
|
||||
} else if (rc == -1) {
|
||||
errno = -rc;
|
||||
qb_util_perror(LOG_WARNING, "job->poll");
|
||||
}
|
||||
}
|
||||
timer_todo = 0;
|
||||
if (l->timer_source && l->timer_source->poll) {
|
||||
rc = l->timer_source->poll(l->timer_source, 0);
|
||||
if (rc > 0) {
|
||||
timer_todo = rc;
|
||||
} else if (rc == -1) {
|
||||
errno = -rc;
|
||||
qb_util_perror(LOG_WARNING, "timer->poll");
|
||||
}
|
||||
}
|
||||
if (remaining_todo > 0 || timer_todo > 0) {
|
||||
/*
|
||||
* if there are remaining todos or timer todos then don't wait.
|
||||
*/
|
||||
ms_timeout = 0;
|
||||
} else if (job_todo > 0) {
|
||||
/*
|
||||
* if we only have jobs to do (not timers or old todos)
|
||||
* then set a non-zero timeout. Jobs can spin out of
|
||||
* control if someone keeps adding them.
|
||||
*/
|
||||
ms_timeout = 50;
|
||||
} else {
|
||||
if (l->timer_source) {
|
||||
ms_timeout = qb_loop_timer_msec_duration_to_expire(l->timer_source);
|
||||
} else {
|
||||
ms_timeout = -1;
|
||||
}
|
||||
}
|
||||
rc = l->fd_source->poll(l->fd_source, ms_timeout);
|
||||
if (rc < 0) {
|
||||
errno = -rc;
|
||||
qb_util_perror(LOG_WARNING, "fd->poll");
|
||||
}
|
||||
|
||||
remaining_todo = 0;
|
||||
for (p = QB_LOOP_HIGH; p >= QB_LOOP_LOW; p--) {
|
||||
if (p >= p_stop) {
|
||||
qb_loop_run_level(&l->level[p]);
|
||||
if (l->stop_requested) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
remaining_todo += l->level[p].todo;
|
||||
}
|
||||
} while (!l->stop_requested);
|
||||
}
|
||||
108
lib/loop_int.h
Normal file
108
lib/loop_int.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QB_LOOP_INT_DEFINED
|
||||
#define QB_LOOP_INT_DEFINED
|
||||
|
||||
#include <qb/qbloop.h>
|
||||
|
||||
struct qb_loop;
|
||||
struct qb_loop_item;
|
||||
|
||||
enum qb_loop_type {
|
||||
QB_LOOP_FD,
|
||||
QB_LOOP_JOB,
|
||||
QB_LOOP_TIMER,
|
||||
QB_LOOP_SIG,
|
||||
};
|
||||
|
||||
struct qb_loop_item {
|
||||
struct qb_list_head list;
|
||||
struct qb_loop_source *source;
|
||||
void *user_data;
|
||||
enum qb_loop_type type;
|
||||
};
|
||||
|
||||
struct qb_loop_level {
|
||||
enum qb_loop_priority priority;
|
||||
int32_t to_process;
|
||||
int32_t todo;
|
||||
struct qb_list_head wait_head;
|
||||
struct qb_list_head job_head;
|
||||
struct qb_loop *l;
|
||||
};
|
||||
|
||||
struct qb_loop_source {
|
||||
struct qb_loop *l;
|
||||
void (*dispatch_and_take_back)(struct qb_loop_item *i,
|
||||
enum qb_loop_priority p);
|
||||
int32_t (*poll)(struct qb_loop_source* s, int32_t ms_timeout);
|
||||
};
|
||||
|
||||
struct qb_loop {
|
||||
struct qb_loop_level level[3];
|
||||
int32_t stop_requested;
|
||||
struct qb_loop_source * timer_source;
|
||||
struct qb_loop_source * job_source;
|
||||
struct qb_loop_source * fd_source;
|
||||
struct qb_loop_source * signal_source;
|
||||
};
|
||||
|
||||
struct qb_loop *
|
||||
qb_loop_default_get(void);
|
||||
|
||||
struct qb_loop_source *
|
||||
qb_loop_jobs_create(struct qb_loop *l);
|
||||
|
||||
struct qb_loop_source*
|
||||
qb_loop_timer_create(struct qb_loop *l);
|
||||
|
||||
struct qb_loop_source*
|
||||
qb_loop_poll_create(struct qb_loop *l);
|
||||
|
||||
struct qb_loop_source *
|
||||
qb_loop_signals_create(struct qb_loop *l);
|
||||
|
||||
void qb_loop_jobs_destroy(struct qb_loop *l);
|
||||
|
||||
void qb_loop_timer_destroy(struct qb_loop *l);
|
||||
|
||||
void qb_loop_poll_destroy(struct qb_loop *l);
|
||||
|
||||
void qb_loop_signals_destroy(struct qb_loop *l);
|
||||
|
||||
int32_t qb_loop_timer_msec_duration_to_expire(struct qb_loop_source *timer_source);
|
||||
|
||||
void qb_loop_level_item_add(struct qb_loop_level *level,
|
||||
struct qb_loop_item *job);
|
||||
|
||||
void qb_loop_level_item_del(struct qb_loop_level *level,
|
||||
struct qb_loop_item *job);
|
||||
|
||||
enum qb_poll_entry_state {
|
||||
QB_POLL_ENTRY_EMPTY,
|
||||
QB_POLL_ENTRY_JOBLIST,
|
||||
QB_POLL_ENTRY_DELETED,
|
||||
QB_POLL_ENTRY_ACTIVE,
|
||||
};
|
||||
|
||||
#endif /* QB_LOOP_INT_DEFINED */
|
||||
|
||||
168
lib/loop_job.c
Normal file
168
lib/loop_job.c
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qblist.h>
|
||||
#include <qb/qbloop.h>
|
||||
#include "loop_int.h"
|
||||
#include "util_int.h"
|
||||
|
||||
struct qb_loop_job {
|
||||
struct qb_loop_item item;
|
||||
qb_loop_job_dispatch_fn dispatch_fn;
|
||||
};
|
||||
|
||||
static void
|
||||
job_dispatch(struct qb_loop_item *item, enum qb_loop_priority p)
|
||||
{
|
||||
struct qb_loop_job *job = qb_list_entry(item, struct qb_loop_job, item);
|
||||
|
||||
job->dispatch_fn(job->item.user_data);
|
||||
free(job);
|
||||
|
||||
/*
|
||||
* this is a one-shot so don't re-add
|
||||
*/
|
||||
}
|
||||
|
||||
static int32_t
|
||||
get_more_jobs(struct qb_loop_source *s, int32_t ms_timeout)
|
||||
{
|
||||
int32_t p;
|
||||
int32_t new_jobs = 0;
|
||||
int32_t level_jobs = 0;
|
||||
|
||||
/*
|
||||
* this is simple, move jobs from wait_head to job_head
|
||||
*/
|
||||
for (p = QB_LOOP_LOW; p <= QB_LOOP_HIGH; p++) {
|
||||
if (!qb_list_empty(&s->l->level[p].wait_head)) {
|
||||
level_jobs = qb_list_length(&s->l->level[p].wait_head);
|
||||
new_jobs += level_jobs;
|
||||
qb_list_splice(&s->l->level[p].wait_head,
|
||||
s->l->level[p].job_head.prev);
|
||||
qb_list_init(&s->l->level[p].wait_head);
|
||||
s->l->level[p].todo += level_jobs;
|
||||
}
|
||||
}
|
||||
return new_jobs;
|
||||
}
|
||||
|
||||
struct qb_loop_source *
|
||||
qb_loop_jobs_create(struct qb_loop *l)
|
||||
{
|
||||
struct qb_loop_source *s = malloc(sizeof(struct qb_loop_source));
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
s->l = l;
|
||||
s->dispatch_and_take_back = job_dispatch;
|
||||
s->poll = get_more_jobs;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
qb_loop_jobs_destroy(struct qb_loop *l)
|
||||
{
|
||||
free(l->job_source);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_job_add(struct qb_loop *lp,
|
||||
enum qb_loop_priority p,
|
||||
void *data, qb_loop_job_dispatch_fn dispatch_fn)
|
||||
{
|
||||
struct qb_loop_job *job;
|
||||
struct qb_loop *l = lp;
|
||||
|
||||
if (l == NULL) {
|
||||
l = qb_loop_default_get();
|
||||
}
|
||||
if (l == NULL || dispatch_fn == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (p < QB_LOOP_LOW || p > QB_LOOP_HIGH) {
|
||||
return -EINVAL;
|
||||
}
|
||||
job = malloc(sizeof(struct qb_loop_job));
|
||||
if (job == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
job->dispatch_fn = dispatch_fn;
|
||||
job->item.user_data = data;
|
||||
job->item.source = l->job_source;
|
||||
job->item.type = QB_LOOP_JOB;
|
||||
|
||||
qb_list_init(&job->item.list);
|
||||
qb_list_add_tail(&job->item.list, &l->level[p].wait_head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_job_del(struct qb_loop *lp,
|
||||
enum qb_loop_priority p,
|
||||
void *data, qb_loop_job_dispatch_fn dispatch_fn)
|
||||
{
|
||||
struct qb_loop_job *job;
|
||||
struct qb_loop_item *item;
|
||||
struct qb_loop *l = lp;
|
||||
|
||||
if (l == NULL) {
|
||||
l = qb_loop_default_get();
|
||||
}
|
||||
if (l == NULL || dispatch_fn == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (p > QB_LOOP_HIGH) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
qb_list_for_each_entry(item, &l->level[p].wait_head, list) {
|
||||
job = (struct qb_loop_job *)item;
|
||||
if (job->dispatch_fn == dispatch_fn &&
|
||||
job->item.user_data == data &&
|
||||
job->item.type == QB_LOOP_JOB) {
|
||||
qb_list_del(&job->item.list);
|
||||
free(job);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
qb_list_for_each_entry(item, &l->level[p].job_head, list) {
|
||||
|
||||
if (item->type != QB_LOOP_JOB) {
|
||||
continue;
|
||||
}
|
||||
job = (struct qb_loop_job *)item;
|
||||
if (job->dispatch_fn == dispatch_fn &&
|
||||
job->item.user_data == data) {
|
||||
qb_loop_level_item_del(&l->level[p], item);
|
||||
qb_util_log(LOG_DEBUG, "deleting job in JOBLIST");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
991
lib/loop_poll.c
Normal file
991
lib/loop_poll.c
Normal file
@ -0,0 +1,991 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_EPOLL_H
|
||||
#include <sys/epoll.h>
|
||||
#ifndef epoll_create1
|
||||
int epoll_create1(int flags);
|
||||
#endif /* workaround a set of sparc and alpha broken headers */
|
||||
#endif /* HAVE_SYS_EPOLL_H */
|
||||
|
||||
#ifdef HAVE_SYS_POLL_H
|
||||
#include <sys/poll.h>
|
||||
#endif /* HAVE_SYS_POLL_H */
|
||||
#ifndef S_SPLINT_S
|
||||
#endif /* S_SPLINT_S */
|
||||
#include <signal.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qblist.h>
|
||||
#include <qb/qbarray.h>
|
||||
#include <qb/qbloop.h>
|
||||
#include <qb/qbutil.h>
|
||||
#include "loop_int.h"
|
||||
#include "util_int.h"
|
||||
|
||||
/*
|
||||
* Define this to log slow (>10ms) jobs.
|
||||
*/
|
||||
#undef DEBUG_DISPATCH_TIME
|
||||
|
||||
/* logs, std(in|out|err), pipe */
|
||||
#define POLL_FDS_USED_MISC 50
|
||||
|
||||
struct qb_poll_entry;
|
||||
|
||||
typedef int32_t(*qb_poll_add_to_jobs_fn) (struct qb_loop * l,
|
||||
struct qb_poll_entry * pe);
|
||||
|
||||
struct qb_poll_entry {
|
||||
struct qb_loop_item item;
|
||||
qb_loop_poll_dispatch_fn poll_dispatch_fn;
|
||||
enum qb_loop_priority p;
|
||||
uint32_t install_pos;
|
||||
struct pollfd ufd;
|
||||
qb_poll_add_to_jobs_fn add_to_jobs;
|
||||
uint32_t runs;
|
||||
enum qb_poll_entry_state state;
|
||||
uint32_t check;
|
||||
};
|
||||
|
||||
struct qb_poll_source {
|
||||
struct qb_loop_source s;
|
||||
#ifdef HAVE_EPOLL
|
||||
int32_t epollfd;
|
||||
#else
|
||||
struct pollfd *ufds;
|
||||
#endif /* HAVE_EPOLL */
|
||||
int32_t poll_entry_count;
|
||||
qb_array_t *poll_entries;
|
||||
qb_loop_poll_low_fds_event_fn low_fds_event_fn;
|
||||
int32_t not_enough_fds;
|
||||
};
|
||||
|
||||
static int32_t _qb_signal_add_to_jobs_(struct qb_loop *l,
|
||||
struct qb_poll_entry *pe);
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
static int32_t
|
||||
_poll_to_epoll_event_(int32_t event)
|
||||
{
|
||||
int32_t out = 0;
|
||||
if (event & POLLIN)
|
||||
out |= EPOLLIN;
|
||||
if (event & POLLOUT)
|
||||
out |= EPOLLOUT;
|
||||
if (event & POLLPRI)
|
||||
out |= EPOLLPRI;
|
||||
if (event & POLLERR)
|
||||
out |= EPOLLERR;
|
||||
if (event & POLLHUP)
|
||||
out |= EPOLLHUP;
|
||||
if (event & POLLNVAL)
|
||||
out |= EPOLLERR;
|
||||
return out;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_epoll_to_poll_event_(int32_t event)
|
||||
{
|
||||
int32_t out = 0;
|
||||
if (event & EPOLLIN)
|
||||
out |= POLLIN;
|
||||
if (event & EPOLLOUT)
|
||||
out |= POLLOUT;
|
||||
if (event & EPOLLPRI)
|
||||
out |= POLLPRI;
|
||||
if (event & EPOLLERR)
|
||||
out |= POLLERR;
|
||||
if (event & EPOLLHUP)
|
||||
out |= POLLHUP;
|
||||
return out;
|
||||
}
|
||||
#endif /* HAVE_EPOLL */
|
||||
|
||||
static void
|
||||
_poll_entry_check_generate_(struct qb_poll_entry *pe)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
for (i = 0; i < 200; i++) {
|
||||
pe->check = random();
|
||||
|
||||
if (pe->check != 0 && pe->check != 0xffffffff) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_EPOLL)
|
||||
static int32_t
|
||||
_poll_entry_from_handle_(struct qb_poll_source *s,
|
||||
uint64_t handle_in, struct qb_poll_entry **pe_pt)
|
||||
{
|
||||
int32_t res = 0;
|
||||
uint32_t check = ((uint32_t) (((uint64_t) handle_in) >> 32));
|
||||
uint32_t handle = handle_in & 0xffffffff;
|
||||
struct qb_poll_entry *pe;
|
||||
|
||||
res = qb_array_index(s->poll_entries, handle, (void **)&pe);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
if (pe->check != check) {
|
||||
return -EINVAL;
|
||||
}
|
||||
*pe_pt = pe;
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_EPOLL */
|
||||
|
||||
static void
|
||||
_poll_entry_mark_deleted_(struct qb_poll_entry *pe)
|
||||
{
|
||||
pe->ufd.fd = -1;
|
||||
pe->state = QB_POLL_ENTRY_DELETED;
|
||||
pe->check = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_poll_entry_empty_(struct qb_poll_entry *pe)
|
||||
{
|
||||
memset(pe, 0, sizeof(struct qb_poll_entry));
|
||||
pe->ufd.fd = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
_poll_dispatch_and_take_back_(struct qb_loop_item *item,
|
||||
enum qb_loop_priority p)
|
||||
{
|
||||
struct qb_poll_entry *pe = (struct qb_poll_entry *)item;
|
||||
int32_t res;
|
||||
#ifdef DEBUG_DISPATCH_TIME
|
||||
uint64_t start;
|
||||
uint64_t stop;
|
||||
int32_t log_warn = QB_FALSE;
|
||||
|
||||
start = qb_util_nano_current_get();
|
||||
#endif /* DEBUG_DISPATCH_TIME */
|
||||
|
||||
assert(pe->state == QB_POLL_ENTRY_JOBLIST);
|
||||
assert(pe->item.type == QB_LOOP_FD);
|
||||
|
||||
res = pe->poll_dispatch_fn(pe->ufd.fd,
|
||||
pe->ufd.revents,
|
||||
pe->item.user_data);
|
||||
if (res < 0) {
|
||||
_poll_entry_mark_deleted_(pe);
|
||||
} else {
|
||||
pe->state = QB_POLL_ENTRY_ACTIVE;
|
||||
pe->ufd.revents = 0;
|
||||
}
|
||||
#ifdef DEBUG_DISPATCH_TIME
|
||||
if (pe->state == QB_POLL_ENTRY_ACTIVE) {
|
||||
pe->runs++;
|
||||
if ((pe->runs % 50) == 0) {
|
||||
log_warn = QB_TRUE;
|
||||
}
|
||||
stop = qb_util_nano_current_get();
|
||||
if ((stop - start) > (10 * QB_TIME_NS_IN_MSEC)) {
|
||||
log_warn = QB_TRUE;
|
||||
}
|
||||
|
||||
if (log_warn && pe->item.type == QB_LOOP_FD) {
|
||||
qb_util_log(LOG_INFO,
|
||||
"[fd:%d] dispatch:%p runs:%d duration:%d ms",
|
||||
pe->ufd.fd, pe->poll_dispatch_fn,
|
||||
pe->runs,
|
||||
(int32_t) ((stop -
|
||||
start) / QB_TIME_NS_IN_MSEC));
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG_DISPATCH_TIME */
|
||||
}
|
||||
|
||||
static void
|
||||
_poll_fds_usage_check_(struct qb_poll_source *s)
|
||||
{
|
||||
struct rlimit lim;
|
||||
static int32_t socks_limit = 0;
|
||||
int32_t send_event = 0;
|
||||
int32_t socks_used = 0;
|
||||
int32_t socks_avail = 0;
|
||||
struct qb_poll_entry *pe;
|
||||
int32_t i;
|
||||
|
||||
if (socks_limit == 0) {
|
||||
if (getrlimit(RLIMIT_NOFILE, &lim) == -1) {
|
||||
qb_util_perror(LOG_WARNING, "getrlimit");
|
||||
return;
|
||||
}
|
||||
socks_limit = lim.rlim_cur;
|
||||
socks_limit -= POLL_FDS_USED_MISC;
|
||||
if (socks_limit < 0) {
|
||||
socks_limit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < s->poll_entry_count; i++) {
|
||||
assert(qb_array_index(s->poll_entries, i, (void **)&pe) == 0);
|
||||
if ((pe->state == QB_POLL_ENTRY_ACTIVE ||
|
||||
pe->state == QB_POLL_ENTRY_JOBLIST) && pe->ufd.fd != -1) {
|
||||
socks_used++;
|
||||
}
|
||||
if (pe->state == QB_POLL_ENTRY_DELETED) {
|
||||
_poll_entry_empty_(pe);
|
||||
}
|
||||
}
|
||||
|
||||
socks_avail = socks_limit - socks_used;
|
||||
if (socks_avail < 0) {
|
||||
socks_avail = 0;
|
||||
}
|
||||
send_event = 0;
|
||||
if (s->not_enough_fds) {
|
||||
if (socks_avail > 2) {
|
||||
s->not_enough_fds = 0;
|
||||
send_event = 1;
|
||||
}
|
||||
} else {
|
||||
if (socks_avail <= 1) {
|
||||
s->not_enough_fds = 1;
|
||||
send_event = 1;
|
||||
}
|
||||
}
|
||||
if (send_event && s->low_fds_event_fn) {
|
||||
s->low_fds_event_fn(s->not_enough_fds, socks_avail);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
#define MAX_EVENTS 12
|
||||
static int32_t
|
||||
_poll_and_add_to_jobs_(struct qb_loop_source *src, int32_t ms_timeout)
|
||||
{
|
||||
int32_t i;
|
||||
int32_t res;
|
||||
int32_t event_count;
|
||||
int32_t new_jobs = 0;
|
||||
struct qb_poll_entry *pe = NULL;
|
||||
struct qb_poll_source *s = (struct qb_poll_source *)src;
|
||||
struct epoll_event events[MAX_EVENTS];
|
||||
|
||||
_poll_fds_usage_check_(s);
|
||||
|
||||
retry_poll:
|
||||
|
||||
event_count = epoll_wait(s->epollfd, events, MAX_EVENTS, ms_timeout);
|
||||
|
||||
if (errno == EINTR && event_count == -1) {
|
||||
goto retry_poll;
|
||||
} else if (event_count == -1) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (i = 0; i < event_count; i++) {
|
||||
res = _poll_entry_from_handle_(s, events[i].data.u64, &pe);
|
||||
if (res != 0) {
|
||||
qb_util_log(LOG_WARNING,
|
||||
"can't find poll entry for new event.");
|
||||
continue;
|
||||
}
|
||||
if (pe->ufd.fd == -1 || pe->state == QB_POLL_ENTRY_DELETED) {
|
||||
qb_util_log(LOG_WARNING,
|
||||
"can't post new event to a deleted entry.");
|
||||
/*
|
||||
* empty/deleted
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (events[i].events == pe->ufd.revents ||
|
||||
pe->state == QB_POLL_ENTRY_JOBLIST) {
|
||||
/*
|
||||
* entry already in the job queue.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
pe->ufd.revents = _epoll_to_poll_event_(events[i].events);
|
||||
|
||||
new_jobs += pe->add_to_jobs(src->l, pe);
|
||||
}
|
||||
|
||||
return new_jobs;
|
||||
}
|
||||
#else
|
||||
static int32_t
|
||||
_poll_and_add_to_jobs_(struct qb_loop_source *src, int32_t ms_timeout)
|
||||
{
|
||||
int32_t i;
|
||||
int32_t res;
|
||||
int32_t new_jobs = 0;
|
||||
struct qb_poll_entry *pe;
|
||||
struct qb_poll_source *s = (struct qb_poll_source *)src;
|
||||
|
||||
_poll_fds_usage_check_(s);
|
||||
|
||||
for (i = 0; i < s->poll_entry_count; i++) {
|
||||
assert(qb_array_index(s->poll_entries, i, (void **)&pe) == 0);
|
||||
memcpy(&s->ufds[i], &pe->ufd, sizeof(struct pollfd));
|
||||
}
|
||||
|
||||
retry_poll:
|
||||
res = poll(s->ufds, s->poll_entry_count, ms_timeout);
|
||||
if (errno == EINTR && res == -1) {
|
||||
goto retry_poll;
|
||||
} else if (res == -1) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (i = 0; i < s->poll_entry_count; i++) {
|
||||
if (s->ufds[i].fd == -1 || s->ufds[i].revents == 0) {
|
||||
/*
|
||||
* empty entry
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
assert(qb_array_index(s->poll_entries, i, (void **)&pe) == 0);
|
||||
if (pe->state != QB_POLL_ENTRY_ACTIVE ||
|
||||
s->ufds[i].revents == pe->ufd.revents) {
|
||||
/*
|
||||
* Wrong state to accept an event.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
pe->ufd.revents = s->ufds[i].revents;
|
||||
new_jobs += pe->add_to_jobs(src->l, pe);
|
||||
}
|
||||
|
||||
return new_jobs;
|
||||
}
|
||||
#endif /* HAVE_EPOLL */
|
||||
|
||||
struct qb_loop_source *
|
||||
qb_loop_poll_create(struct qb_loop *l)
|
||||
{
|
||||
struct qb_poll_source *s = malloc(sizeof(struct qb_poll_source));
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
s->s.l = l;
|
||||
s->s.dispatch_and_take_back = _poll_dispatch_and_take_back_;
|
||||
s->s.poll = _poll_and_add_to_jobs_;
|
||||
|
||||
s->poll_entries = qb_array_create_2(16, sizeof(struct qb_poll_entry), 16);
|
||||
s->poll_entry_count = 0;
|
||||
s->low_fds_event_fn = NULL;
|
||||
s->not_enough_fds = 0;
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
s->epollfd = epoll_create1(EPOLL_CLOEXEC);
|
||||
#else
|
||||
s->ufds = 0;
|
||||
#endif /* HAVE_EPOLL */
|
||||
|
||||
return (struct qb_loop_source *)s;
|
||||
}
|
||||
|
||||
void
|
||||
qb_loop_poll_destroy(struct qb_loop *l)
|
||||
{
|
||||
struct qb_poll_source *s = (struct qb_poll_source *)l->fd_source;
|
||||
qb_array_free(s->poll_entries);
|
||||
#ifdef HAVE_EPOLL
|
||||
if (s->epollfd != -1) {
|
||||
close(s->epollfd);
|
||||
s->epollfd = -1;
|
||||
}
|
||||
#endif /* HAVE_EPOLL */
|
||||
free(s);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_poll_low_fds_event_set(struct qb_loop *l,
|
||||
qb_loop_poll_low_fds_event_fn fn)
|
||||
{
|
||||
struct qb_poll_source *s = (struct qb_poll_source *)l->fd_source;
|
||||
s->low_fds_event_fn = fn;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_get_empty_array_position_(struct qb_poll_source *s)
|
||||
{
|
||||
int32_t found = 0;
|
||||
uint32_t install_pos;
|
||||
int32_t res = 0;
|
||||
struct qb_poll_entry *pe;
|
||||
#ifndef HAVE_EPOLL
|
||||
struct pollfd *ufds;
|
||||
int32_t new_size = 0;
|
||||
#endif /* HAVE_EPOLL */
|
||||
|
||||
for (found = 0, install_pos = 0;
|
||||
install_pos < s->poll_entry_count; install_pos++) {
|
||||
assert(qb_array_index
|
||||
(s->poll_entries, install_pos, (void **)&pe) == 0);
|
||||
if (pe->state == QB_POLL_ENTRY_EMPTY) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
/*
|
||||
* Grow pollfd list
|
||||
*/
|
||||
res = qb_array_grow(s->poll_entries, s->poll_entry_count + 1);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
#ifndef HAVE_EPOLL
|
||||
new_size = (s->poll_entry_count + 1) * sizeof(struct pollfd);
|
||||
ufds = realloc(s->ufds, new_size);
|
||||
if (ufds == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
s->ufds = ufds;
|
||||
#endif /* HAVE_EPOLL */
|
||||
|
||||
s->poll_entry_count += 1;
|
||||
install_pos = s->poll_entry_count - 1;
|
||||
}
|
||||
return install_pos;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_poll_add_(struct qb_loop *l,
|
||||
enum qb_loop_priority p,
|
||||
int32_t fd, int32_t events, void *data, struct qb_poll_entry **pe_pt)
|
||||
{
|
||||
struct qb_poll_entry *pe;
|
||||
uint32_t install_pos;
|
||||
int32_t res = 0;
|
||||
struct qb_poll_source *s;
|
||||
#ifdef HAVE_EPOLL
|
||||
struct epoll_event ev;
|
||||
#endif /* HAVE_EPOLL */
|
||||
|
||||
if (l == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s = (struct qb_poll_source *)l->fd_source;
|
||||
|
||||
install_pos = _get_empty_array_position_(s);
|
||||
|
||||
assert(qb_array_index(s->poll_entries, install_pos, (void **)&pe) == 0);
|
||||
pe->state = QB_POLL_ENTRY_ACTIVE;
|
||||
pe->install_pos = install_pos;
|
||||
_poll_entry_check_generate_(pe);
|
||||
pe->ufd.fd = fd;
|
||||
pe->ufd.events = events;
|
||||
pe->ufd.revents = 0;
|
||||
pe->item.user_data = data;
|
||||
pe->item.source = (struct qb_loop_source *)l->fd_source;
|
||||
pe->p = p;
|
||||
pe->runs = 0;
|
||||
#ifdef HAVE_EPOLL
|
||||
ev.events = _poll_to_epoll_event_(events);
|
||||
ev.data.u64 = (((uint64_t) (pe->check)) << 32) | pe->install_pos;
|
||||
if (epoll_ctl(s->epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "epoll_ctl(add)");
|
||||
}
|
||||
#endif /* HAVE_EPOLL */
|
||||
*pe_pt = pe;
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_qb_poll_add_to_jobs_(struct qb_loop *l, struct qb_poll_entry *pe)
|
||||
{
|
||||
assert(pe->item.type == QB_LOOP_FD);
|
||||
qb_loop_level_item_add(&l->level[pe->p], &pe->item);
|
||||
pe->state = QB_POLL_ENTRY_JOBLIST;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_poll_add(struct qb_loop * lp,
|
||||
enum qb_loop_priority p,
|
||||
int32_t fd,
|
||||
int32_t events,
|
||||
void *data, qb_loop_poll_dispatch_fn dispatch_fn)
|
||||
{
|
||||
struct qb_poll_entry *pe = NULL;
|
||||
int32_t size;
|
||||
int32_t new_size;
|
||||
int32_t res;
|
||||
struct qb_loop *l = lp;
|
||||
|
||||
if (l == NULL) {
|
||||
l = qb_loop_default_get();
|
||||
}
|
||||
|
||||
size = ((struct qb_poll_source *)l->fd_source)->poll_entry_count;
|
||||
res = _poll_add_(l, p, fd, events, data, &pe);
|
||||
new_size = ((struct qb_poll_source *)l->fd_source)->poll_entry_count;
|
||||
|
||||
pe->poll_dispatch_fn = dispatch_fn;
|
||||
pe->item.type = QB_LOOP_FD;
|
||||
pe->add_to_jobs = _qb_poll_add_to_jobs_;
|
||||
|
||||
if (new_size > size) {
|
||||
qb_util_log(LOG_TRACE,
|
||||
"grown poll array to %d for FD %d", new_size, fd);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_poll_mod(struct qb_loop * lp,
|
||||
enum qb_loop_priority p,
|
||||
int32_t fd,
|
||||
int32_t events,
|
||||
void *data, qb_loop_poll_dispatch_fn dispatch_fn)
|
||||
{
|
||||
uint32_t i;
|
||||
int32_t res = 0;
|
||||
struct qb_poll_entry *pe;
|
||||
struct qb_poll_source *s;
|
||||
#ifdef HAVE_EPOLL
|
||||
struct epoll_event ev;
|
||||
#endif /* HAVE_EPOLL */
|
||||
struct qb_loop *l = lp;
|
||||
|
||||
if (l == NULL) {
|
||||
l = qb_loop_default_get();
|
||||
}
|
||||
s = (struct qb_poll_source *)l->fd_source;
|
||||
|
||||
/*
|
||||
* Find file descriptor to modify events and dispatch function
|
||||
*/
|
||||
for (i = 0; i < s->poll_entry_count; i++) {
|
||||
assert(qb_array_index(s->poll_entries, i, (void **)&pe) == 0);
|
||||
if (pe->ufd.fd != fd) {
|
||||
continue;
|
||||
}
|
||||
if (pe->state == QB_POLL_ENTRY_DELETED || pe->check == 0) {
|
||||
qb_util_log(LOG_ERR,
|
||||
"poll_mod : can't modify entry already deleted");
|
||||
return -EBADF;
|
||||
}
|
||||
pe->poll_dispatch_fn = dispatch_fn;
|
||||
pe->item.user_data = data;
|
||||
pe->p = p;
|
||||
if (pe->ufd.events != events) {
|
||||
#ifdef HAVE_EPOLL
|
||||
ev.events = _poll_to_epoll_event_(events);
|
||||
ev.data.u64 = (((uint64_t) (pe->check)) << 32) | i;
|
||||
if (epoll_ctl(s->epollfd, EPOLL_CTL_MOD, fd, &ev) == -1) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "epoll_ctl(mod)");
|
||||
}
|
||||
#endif /* HAVE_EPOLL */
|
||||
pe->ufd.events = events;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_poll_del(struct qb_loop * lp, int32_t fd)
|
||||
{
|
||||
int32_t i;
|
||||
int32_t res = 0;
|
||||
struct qb_poll_entry *pe;
|
||||
struct qb_poll_source *s;
|
||||
struct qb_loop *l = lp;
|
||||
|
||||
if (l == NULL) {
|
||||
l = qb_loop_default_get();
|
||||
}
|
||||
s = (struct qb_poll_source *)l->fd_source;
|
||||
for (i = 0; i < s->poll_entry_count; i++) {
|
||||
assert(qb_array_index(s->poll_entries, i, (void **)&pe) == 0);
|
||||
if (pe->ufd.fd != fd || pe->item.type != QB_LOOP_FD) {
|
||||
continue;
|
||||
}
|
||||
if (pe->state == QB_POLL_ENTRY_DELETED ||
|
||||
pe->state == QB_POLL_ENTRY_EMPTY) {
|
||||
return 0;
|
||||
}
|
||||
if (pe->state == QB_POLL_ENTRY_JOBLIST) {
|
||||
qb_loop_level_item_del(&l->level[pe->p], &pe->item);
|
||||
}
|
||||
#ifdef HAVE_EPOLL
|
||||
if (epoll_ctl(s->epollfd, EPOLL_CTL_DEL, fd, NULL) == -1) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_WARNING, "epoll_ctl(del)");
|
||||
}
|
||||
#else
|
||||
s->ufds[i].fd = -1;
|
||||
s->ufds[i].events = 0;
|
||||
s->ufds[i].revents = 0;
|
||||
#endif /* HAVE_EPOLL */
|
||||
_poll_entry_mark_deleted_(pe);
|
||||
return res;
|
||||
}
|
||||
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
static int32_t pipe_fds[2] = { -1, -1 };
|
||||
|
||||
struct qb_signal_source {
|
||||
struct qb_loop_source s;
|
||||
struct qb_list_head sig_head;
|
||||
sigset_t signal_superset;
|
||||
};
|
||||
|
||||
struct qb_loop_sig {
|
||||
struct qb_loop_item item;
|
||||
int32_t signal;
|
||||
enum qb_loop_priority p;
|
||||
qb_loop_signal_dispatch_fn dispatch_fn;
|
||||
struct qb_loop_sig *cloned_from;
|
||||
};
|
||||
|
||||
static void
|
||||
_handle_real_signal_(int signal_num, siginfo_t * si, void *context)
|
||||
{
|
||||
int32_t sig = signal_num;
|
||||
int32_t res = 0;
|
||||
|
||||
if (pipe_fds[1] > 0) {
|
||||
try_again:
|
||||
res = write(pipe_fds[1], &sig, sizeof(int32_t));
|
||||
if (res == -1 && errno == EAGAIN) {
|
||||
goto try_again;
|
||||
} else if (res != sizeof(int32_t)) {
|
||||
qb_util_log(LOG_ERR,
|
||||
"failed to write signal to pipe [%d]", res);
|
||||
}
|
||||
}
|
||||
qb_util_log(LOG_TRACE, "got real signal [%d] sent to pipe", sig);
|
||||
}
|
||||
|
||||
static void
|
||||
_signal_dispatch_and_take_back_(struct qb_loop_item *item,
|
||||
enum qb_loop_priority p)
|
||||
{
|
||||
struct qb_loop_sig *sig = (struct qb_loop_sig *)item;
|
||||
int32_t res;
|
||||
|
||||
res = sig->dispatch_fn(sig->signal, sig->item.user_data);
|
||||
if (res != 0) {
|
||||
(void)qb_loop_signal_del(sig->cloned_from->item.source->l,
|
||||
sig->cloned_from);
|
||||
}
|
||||
free(sig);
|
||||
}
|
||||
|
||||
struct qb_loop_source *
|
||||
qb_loop_signals_create(struct qb_loop *l)
|
||||
{
|
||||
int32_t res = 0;
|
||||
struct qb_poll_entry *pe;
|
||||
struct qb_signal_source *s = calloc(1, sizeof(struct qb_signal_source));
|
||||
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
s->s.l = l;
|
||||
s->s.dispatch_and_take_back = _signal_dispatch_and_take_back_;
|
||||
s->s.poll = NULL;
|
||||
qb_list_init(&s->sig_head);
|
||||
sigemptyset(&s->signal_superset);
|
||||
|
||||
if (pipe_fds[0] < 0) {
|
||||
res = pipe(pipe_fds);
|
||||
if (res == -1) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "Can't light pipe");
|
||||
goto error_exit;
|
||||
}
|
||||
(void)qb_sys_fd_nonblock_cloexec_set(pipe_fds[0]);
|
||||
(void)qb_sys_fd_nonblock_cloexec_set(pipe_fds[1]);
|
||||
|
||||
res = _poll_add_(l, QB_LOOP_HIGH,
|
||||
pipe_fds[0], POLLIN, NULL, &pe);
|
||||
if (res == 0) {
|
||||
pe->poll_dispatch_fn = NULL;
|
||||
pe->item.type = QB_LOOP_SIG;
|
||||
pe->add_to_jobs = _qb_signal_add_to_jobs_;
|
||||
} else {
|
||||
qb_util_perror(LOG_ERR, "Can't smoke pipe");
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
return (struct qb_loop_source *)s;
|
||||
|
||||
error_exit:
|
||||
errno = -res;
|
||||
free(s);
|
||||
if (pipe_fds[0] >= 0) {
|
||||
close(pipe_fds[0]);
|
||||
}
|
||||
if (pipe_fds[1] >= 0) {
|
||||
close(pipe_fds[1]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
qb_loop_signals_destroy(struct qb_loop *l)
|
||||
{
|
||||
struct qb_signal_source *s =
|
||||
(struct qb_signal_source *)l->signal_source;
|
||||
struct qb_list_head *list;
|
||||
struct qb_list_head *n;
|
||||
struct qb_loop_item *item;
|
||||
|
||||
close(pipe_fds[0]);
|
||||
pipe_fds[0] = -1;
|
||||
close(pipe_fds[1]);
|
||||
pipe_fds[1] = -1;
|
||||
|
||||
qb_list_for_each_safe(list, n, &s->sig_head) {
|
||||
item = qb_list_entry(list, struct qb_loop_item, list);
|
||||
qb_list_del(&item->list);
|
||||
free(item);
|
||||
}
|
||||
|
||||
free(l->signal_source);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_qb_signal_add_to_jobs_(struct qb_loop *l, struct qb_poll_entry *pe)
|
||||
{
|
||||
struct qb_signal_source *s =
|
||||
(struct qb_signal_source *)l->signal_source;
|
||||
struct qb_list_head *list;
|
||||
struct qb_loop_sig *sig;
|
||||
struct qb_loop_item *item;
|
||||
struct qb_loop_sig *new_sig_job;
|
||||
int32_t the_signal;
|
||||
ssize_t res;
|
||||
int32_t jobs_added = 0;
|
||||
|
||||
res = read(pipe_fds[0], &the_signal, sizeof(int32_t));
|
||||
if (res != sizeof(int32_t)) {
|
||||
qb_util_perror(LOG_WARNING, "failed to read pipe");
|
||||
return 0;
|
||||
}
|
||||
pe->ufd.revents = 0;
|
||||
|
||||
qb_list_for_each(list, &s->sig_head) {
|
||||
item = qb_list_entry(list, struct qb_loop_item, list);
|
||||
sig = (struct qb_loop_sig *)item;
|
||||
if (sig->signal == the_signal) {
|
||||
new_sig_job = calloc(1, sizeof(struct qb_loop_sig));
|
||||
if (new_sig_job == NULL) {
|
||||
return jobs_added;
|
||||
}
|
||||
memcpy(new_sig_job, sig, sizeof(struct qb_loop_sig));
|
||||
|
||||
qb_util_log(LOG_TRACE,
|
||||
"adding signal [%d] to job queue %p",
|
||||
the_signal, sig);
|
||||
|
||||
new_sig_job->cloned_from = sig;
|
||||
qb_loop_level_item_add(&l->level[sig->p],
|
||||
&new_sig_job->item);
|
||||
jobs_added++;
|
||||
}
|
||||
}
|
||||
return jobs_added;
|
||||
}
|
||||
|
||||
static void
|
||||
_adjust_sigactions_(struct qb_signal_source *s)
|
||||
{
|
||||
struct qb_loop_sig *sig;
|
||||
struct qb_loop_item *item;
|
||||
struct sigaction sa;
|
||||
int32_t i;
|
||||
int32_t needed;
|
||||
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = _handle_real_signal_;
|
||||
sigemptyset(&s->signal_superset);
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
/* re-set to default */
|
||||
for (i = 0; i < 30; i++) {
|
||||
needed = QB_FALSE;
|
||||
qb_list_for_each_entry(item, &s->sig_head, list) {
|
||||
sig = (struct qb_loop_sig *)item;
|
||||
if (i == sig->signal) {
|
||||
needed = QB_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (needed) {
|
||||
sigaddset(&s->signal_superset, i);
|
||||
sigaction(i, &sa, NULL);
|
||||
} else {
|
||||
(void)signal(i, SIG_DFL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_signal_add(qb_loop_t * lp,
|
||||
enum qb_loop_priority p,
|
||||
int32_t the_sig,
|
||||
void *data,
|
||||
qb_loop_signal_dispatch_fn dispatch_fn,
|
||||
qb_loop_signal_handle * handle)
|
||||
{
|
||||
struct qb_loop_sig *sig;
|
||||
struct qb_signal_source *s;
|
||||
struct qb_loop *l = lp;
|
||||
|
||||
if (l == NULL) {
|
||||
l = qb_loop_default_get();
|
||||
}
|
||||
if (l == NULL || dispatch_fn == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (p < QB_LOOP_LOW || p > QB_LOOP_HIGH) {
|
||||
return -EINVAL;
|
||||
}
|
||||
s = (struct qb_signal_source *)l->signal_source;
|
||||
sig = calloc(1, sizeof(struct qb_loop_sig));
|
||||
if (sig == NULL) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
sig->dispatch_fn = dispatch_fn;
|
||||
sig->p = p;
|
||||
sig->signal = the_sig;
|
||||
sig->item.user_data = data;
|
||||
sig->item.source = l->signal_source;
|
||||
sig->item.type = QB_LOOP_SIG;
|
||||
|
||||
qb_list_init(&sig->item.list);
|
||||
qb_list_add_tail(&sig->item.list, &s->sig_head);
|
||||
|
||||
if (sigismember(&s->signal_superset, the_sig) != 1) {
|
||||
_adjust_sigactions_(s);
|
||||
}
|
||||
if (handle) {
|
||||
*handle = sig;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_signal_mod(qb_loop_t * lp,
|
||||
enum qb_loop_priority p,
|
||||
int32_t the_sig,
|
||||
void *data,
|
||||
qb_loop_signal_dispatch_fn dispatch_fn,
|
||||
qb_loop_signal_handle handle)
|
||||
{
|
||||
struct qb_signal_source *s;
|
||||
struct qb_loop_sig *sig = (struct qb_loop_sig *)handle;
|
||||
struct qb_loop *l = lp;
|
||||
|
||||
if (l == NULL) {
|
||||
l = qb_loop_default_get();
|
||||
}
|
||||
if (l == NULL || dispatch_fn == NULL || handle == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (p < QB_LOOP_LOW || p > QB_LOOP_HIGH) {
|
||||
return -EINVAL;
|
||||
}
|
||||
s = (struct qb_signal_source *)l->signal_source;
|
||||
|
||||
sig->item.user_data = data;
|
||||
sig->item.type = QB_LOOP_SIG;
|
||||
sig->dispatch_fn = dispatch_fn;
|
||||
sig->p = p;
|
||||
|
||||
if (sig->signal != the_sig) {
|
||||
sig->signal = the_sig;
|
||||
_adjust_sigactions_(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_signal_del(qb_loop_t * lp, qb_loop_signal_handle handle)
|
||||
{
|
||||
struct qb_signal_source *s;
|
||||
struct qb_loop_sig *sig = (struct qb_loop_sig *)handle;
|
||||
struct qb_loop_sig *sig_clone;
|
||||
struct qb_loop *l = lp;
|
||||
struct qb_loop_item *item;
|
||||
|
||||
if (l == NULL) {
|
||||
l = qb_loop_default_get();
|
||||
}
|
||||
if (l == NULL || handle == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
s = (struct qb_signal_source *)l->signal_source;
|
||||
|
||||
qb_list_for_each_entry(item, &l->level[sig->p].wait_head, list) {
|
||||
if (item->type != QB_LOOP_SIG) {
|
||||
continue;
|
||||
}
|
||||
sig_clone = (struct qb_loop_sig *)item;
|
||||
if (sig_clone->cloned_from == sig) {
|
||||
qb_util_log(LOG_TRACE, "deleting sig in WAITLIST");
|
||||
qb_list_del(&sig_clone->item.list);
|
||||
free(sig_clone);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qb_list_for_each_entry(item, &l->level[sig->p].job_head, list) {
|
||||
if (item->type != QB_LOOP_SIG) {
|
||||
continue;
|
||||
}
|
||||
sig_clone = (struct qb_loop_sig *)item;
|
||||
if (sig_clone->cloned_from == sig) {
|
||||
qb_loop_level_item_del(&l->level[sig->p], item);
|
||||
qb_util_log(LOG_TRACE, "deleting sig in JOBLIST");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qb_list_del(&sig->item.list);
|
||||
free(sig);
|
||||
_adjust_sigactions_(s);
|
||||
return 0;
|
||||
}
|
||||
287
lib/loop_timerlist.c
Normal file
287
lib/loop_timerlist.c
Normal file
@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "os_base.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qblist.h>
|
||||
#include <qb/qbarray.h>
|
||||
#include <qb/qbloop.h>
|
||||
#include "loop_int.h"
|
||||
#include "util_int.h"
|
||||
#include "tlist.h"
|
||||
|
||||
struct qb_loop_timer {
|
||||
struct qb_loop_item item;
|
||||
qb_loop_timer_dispatch_fn dispatch_fn;
|
||||
enum qb_loop_priority p;
|
||||
timer_handle timerlist_handle;
|
||||
enum qb_poll_entry_state state;
|
||||
uint32_t check;
|
||||
uint32_t install_pos;
|
||||
};
|
||||
|
||||
struct qb_timer_source {
|
||||
struct qb_loop_source s;
|
||||
struct timerlist timerlist;
|
||||
qb_array_t *timers;
|
||||
size_t timer_entry_count;
|
||||
};
|
||||
|
||||
static void
|
||||
timer_dispatch(struct qb_loop_item *item, enum qb_loop_priority p)
|
||||
{
|
||||
struct qb_loop_timer *timer = (struct qb_loop_timer *)item;
|
||||
|
||||
assert(timer->state == QB_POLL_ENTRY_JOBLIST);
|
||||
timer->check = 0;
|
||||
timer->dispatch_fn(timer->item.user_data);
|
||||
timer->state = QB_POLL_ENTRY_EMPTY;
|
||||
}
|
||||
|
||||
static int32_t expired_timers;
|
||||
static void
|
||||
make_job_from_tmo(void *data)
|
||||
{
|
||||
struct qb_loop_timer *t = (struct qb_loop_timer *)data;
|
||||
struct qb_loop *l = t->item.source->l;
|
||||
|
||||
assert(t->state == QB_POLL_ENTRY_ACTIVE);
|
||||
qb_loop_level_item_add(&l->level[t->p], &t->item);
|
||||
t->state = QB_POLL_ENTRY_JOBLIST;
|
||||
expired_timers++;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
expire_the_timers(struct qb_loop_source *s, int32_t ms_timeout)
|
||||
{
|
||||
struct qb_timer_source *ts = (struct qb_timer_source *)s;
|
||||
expired_timers = 0;
|
||||
timerlist_expire(&ts->timerlist);
|
||||
return expired_timers;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_timer_msec_duration_to_expire(struct qb_loop_source * timer_source)
|
||||
{
|
||||
struct qb_timer_source *my_src = (struct qb_timer_source *)timer_source;
|
||||
uint64_t left = timerlist_msec_duration_to_expire(&my_src->timerlist);
|
||||
if (left != -1 && left > 0xFFFFFFFF) {
|
||||
left = 0xFFFFFFFE;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
struct qb_loop_source *
|
||||
qb_loop_timer_create(struct qb_loop *l)
|
||||
{
|
||||
struct qb_timer_source *my_src = malloc(sizeof(struct qb_timer_source));
|
||||
if (my_src == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
my_src->s.l = l;
|
||||
my_src->s.dispatch_and_take_back = timer_dispatch;
|
||||
my_src->s.poll = expire_the_timers;
|
||||
|
||||
timerlist_init(&my_src->timerlist);
|
||||
my_src->timers = qb_array_create_2(16, sizeof(struct qb_loop_timer), 16);
|
||||
my_src->timer_entry_count = 0;
|
||||
|
||||
return (struct qb_loop_source *)my_src;
|
||||
}
|
||||
|
||||
void
|
||||
qb_loop_timer_destroy(struct qb_loop *l)
|
||||
{
|
||||
struct qb_timer_source *my_src =
|
||||
(struct qb_timer_source *)l->timer_source;
|
||||
qb_array_free(my_src->timers);
|
||||
free(l->timer_source);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_timer_from_handle_(struct qb_timer_source *s,
|
||||
qb_loop_timer_handle handle_in,
|
||||
struct qb_loop_timer **timer_pt)
|
||||
{
|
||||
int32_t rc;
|
||||
uint32_t check;
|
||||
uint32_t install_pos;
|
||||
struct qb_loop_timer *timer;
|
||||
|
||||
if (handle_in == 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
check = ((uint32_t) (((uint64_t) handle_in) >> 32));
|
||||
install_pos = handle_in & 0xffffffff;
|
||||
|
||||
rc = qb_array_index(s->timers, install_pos, (void **)&timer);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
if (timer->check != check) {
|
||||
return -EINVAL;
|
||||
}
|
||||
*timer_pt = timer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
_get_empty_array_position_(struct qb_timer_source *s)
|
||||
{
|
||||
int32_t install_pos;
|
||||
int32_t res = 0;
|
||||
struct qb_loop_timer *timer;
|
||||
|
||||
for (install_pos = 0; install_pos < s->timer_entry_count; install_pos++) {
|
||||
assert(qb_array_index(s->timers, install_pos, (void **)&timer)
|
||||
== 0);
|
||||
if (timer->state == QB_POLL_ENTRY_EMPTY) {
|
||||
return install_pos;
|
||||
}
|
||||
}
|
||||
|
||||
res = qb_array_grow(s->timers, s->timer_entry_count + 1);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
s->timer_entry_count++;
|
||||
install_pos = s->timer_entry_count - 1;
|
||||
return install_pos;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_timer_add(struct qb_loop * lp,
|
||||
enum qb_loop_priority p,
|
||||
uint64_t nsec_duration,
|
||||
void *data,
|
||||
qb_loop_timer_dispatch_fn timer_fn,
|
||||
qb_loop_timer_handle * timer_handle_out)
|
||||
{
|
||||
struct qb_loop_timer *t;
|
||||
struct qb_timer_source *my_src;
|
||||
int32_t i;
|
||||
struct qb_loop *l = lp;
|
||||
|
||||
if (l == NULL) {
|
||||
l = qb_loop_default_get();
|
||||
}
|
||||
|
||||
if (l == NULL || timer_fn == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
my_src = (struct qb_timer_source *)l->timer_source;
|
||||
|
||||
i = _get_empty_array_position_(my_src);
|
||||
assert(qb_array_index(my_src->timers, i, (void **)&t) >= 0);
|
||||
t->state = QB_POLL_ENTRY_ACTIVE;
|
||||
t->install_pos = i;
|
||||
t->item.user_data = data;
|
||||
t->item.source = (struct qb_loop_source *)my_src;
|
||||
t->dispatch_fn = timer_fn;
|
||||
t->p = p;
|
||||
qb_list_init(&t->item.list);
|
||||
|
||||
for (i = 0; i < 200; i++) {
|
||||
t->check = random();
|
||||
|
||||
if (t->check != 0 && t->check != 0xffffffff) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (timer_handle_out) {
|
||||
*timer_handle_out = (((uint64_t) (t->check)) << 32) | t->install_pos;
|
||||
}
|
||||
return timerlist_add_duration(&my_src->timerlist,
|
||||
make_job_from_tmo, t,
|
||||
nsec_duration, &t->timerlist_handle);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_timer_del(struct qb_loop * lp, qb_loop_timer_handle th)
|
||||
{
|
||||
struct qb_timer_source *s;
|
||||
struct qb_loop_timer *t;
|
||||
int32_t res;
|
||||
struct qb_loop *l = lp;
|
||||
|
||||
if (l == NULL) {
|
||||
l = qb_loop_default_get();
|
||||
}
|
||||
s = (struct qb_timer_source *)l->timer_source;
|
||||
|
||||
res = _timer_from_handle_(s, th, &t);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (t->state == QB_POLL_ENTRY_DELETED) {
|
||||
qb_util_log(LOG_WARNING, "timer already deleted");
|
||||
return 0;
|
||||
}
|
||||
if (t->state != QB_POLL_ENTRY_ACTIVE &&
|
||||
t->state != QB_POLL_ENTRY_JOBLIST) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (t->state == QB_POLL_ENTRY_JOBLIST) {
|
||||
qb_loop_level_item_del(&l->level[t->p], &t->item);
|
||||
}
|
||||
|
||||
if (t->timerlist_handle) {
|
||||
timerlist_del(&s->timerlist, t->timerlist_handle);
|
||||
}
|
||||
t->state = QB_POLL_ENTRY_EMPTY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
qb_loop_timer_expire_time_get(struct qb_loop * lp, qb_loop_timer_handle th)
|
||||
{
|
||||
struct qb_timer_source *s;
|
||||
struct qb_loop_timer *t;
|
||||
int32_t res;
|
||||
struct qb_loop *l = lp;
|
||||
|
||||
if (l == NULL) {
|
||||
l = qb_loop_default_get();
|
||||
}
|
||||
s = (struct qb_timer_source *)l->timer_source;
|
||||
|
||||
res = _timer_from_handle_(s, th, &t);
|
||||
if (res != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (t->state != QB_POLL_ENTRY_ACTIVE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return timerlist_expire_time(&s->timerlist, t->timerlist_handle);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_loop_timer_is_running(qb_loop_t *l, qb_loop_timer_handle th)
|
||||
{
|
||||
return (qb_loop_timer_expire_time_get(l, th) > 0);
|
||||
}
|
||||
131
lib/map.c
Normal file
131
lib/map.c
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "os_base.h"
|
||||
#include <qb/qbmap.h>
|
||||
#include "map_int.h"
|
||||
|
||||
void
|
||||
qb_map_put(struct qb_map *map, const char *key, const void *value)
|
||||
{
|
||||
map->put(map, key, value);
|
||||
}
|
||||
|
||||
void *
|
||||
qb_map_get(struct qb_map *map, const char *key)
|
||||
{
|
||||
return map->get(map, key);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_map_rm(struct qb_map * map, const char *key)
|
||||
{
|
||||
return map->rm(map, key);
|
||||
}
|
||||
|
||||
size_t
|
||||
qb_map_count_get(struct qb_map * map)
|
||||
{
|
||||
return map->count_get(map);
|
||||
}
|
||||
|
||||
void
|
||||
qb_map_foreach(struct qb_map *map, qb_map_transverse_fn func, void *user_data)
|
||||
{
|
||||
const char *key;
|
||||
void *value;
|
||||
qb_map_iter_t *i = qb_map_iter_create(map);
|
||||
|
||||
for (key = qb_map_iter_next(i, &value);
|
||||
key; key = qb_map_iter_next(i, &value)) {
|
||||
if (func(key, value, user_data)) {
|
||||
goto clean_up;
|
||||
}
|
||||
}
|
||||
clean_up:
|
||||
qb_map_iter_free(i);
|
||||
}
|
||||
|
||||
qb_map_iter_t *
|
||||
qb_map_iter_create(struct qb_map *map)
|
||||
{
|
||||
return map->iter_create(map, NULL);
|
||||
}
|
||||
|
||||
qb_map_iter_t *
|
||||
qb_map_pref_iter_create(qb_map_t * map, const char *prefix)
|
||||
{
|
||||
return map->iter_create(map, prefix);
|
||||
}
|
||||
|
||||
const char *
|
||||
qb_map_iter_next(struct qb_map_iter *i, void **value)
|
||||
{
|
||||
return i->m->iter_next(i, value);
|
||||
}
|
||||
|
||||
void
|
||||
qb_map_iter_free(qb_map_iter_t * i)
|
||||
{
|
||||
i->m->iter_free(i);
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_map_notify_add(qb_map_t * m, const char *key, qb_map_notify_fn fn,
|
||||
int32_t events, void *user_data)
|
||||
{
|
||||
if (key != NULL && events & QB_MAP_NOTIFY_FREE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (m->notify_add) {
|
||||
return m->notify_add(m, key, fn, events, user_data);
|
||||
} else {
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_map_notify_del(qb_map_t * m, const char *key, qb_map_notify_fn fn,
|
||||
int32_t events)
|
||||
{
|
||||
if (m->notify_del) {
|
||||
return m->notify_del(m, key, fn, events, QB_FALSE, NULL);
|
||||
} else {
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_map_notify_del_2(qb_map_t * m, const char *key, qb_map_notify_fn fn,
|
||||
int32_t events, void *user_data)
|
||||
{
|
||||
if (m->notify_del) {
|
||||
return m->notify_del(m, key, fn, events, QB_TRUE, user_data);
|
||||
} else {
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qb_map_destroy(struct qb_map *map)
|
||||
{
|
||||
map->destroy(map);
|
||||
}
|
||||
75
lib/map_int.h
Normal file
75
lib/map_int.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _QB_MAP_INT_H_
|
||||
#define _QB_MAP_INT_H_
|
||||
|
||||
#include <qb/qblist.h>
|
||||
|
||||
struct qb_map;
|
||||
|
||||
typedef void (*qb_map_put_func)(struct qb_map *map, const char* key,
|
||||
const void* value);
|
||||
typedef void* (*qb_map_get_func)(struct qb_map *map, const char* key);
|
||||
typedef int32_t (*qb_map_rm_func)(struct qb_map *map, const char* key);
|
||||
typedef size_t (*qb_map_count_get_func)(struct qb_map *map);
|
||||
typedef void (*qb_map_destroy_func)(struct qb_map *map);
|
||||
typedef qb_map_iter_t* (*qb_map_iter_create_func)(struct qb_map *map,
|
||||
const char* prefix);
|
||||
typedef const char* (*qb_map_iter_next_func)(qb_map_iter_t* i, void** value);
|
||||
typedef void (*qb_map_iter_free_func)(qb_map_iter_t* i);
|
||||
|
||||
typedef int32_t (*qb_map_notify_add_func)(qb_map_t* m, const char* key,
|
||||
qb_map_notify_fn fn, int32_t events,
|
||||
void *user_data);
|
||||
|
||||
typedef int32_t (*qb_map_notify_del_func)(qb_map_t * m, const char *key,
|
||||
qb_map_notify_fn fn,
|
||||
int32_t events,
|
||||
int32_t cmp_userdata,
|
||||
void *user_data);
|
||||
|
||||
struct qb_map {
|
||||
qb_map_put_func put;
|
||||
qb_map_get_func get;
|
||||
qb_map_rm_func rm;
|
||||
qb_map_count_get_func count_get;
|
||||
qb_map_destroy_func destroy;
|
||||
qb_map_iter_create_func iter_create;
|
||||
qb_map_iter_next_func iter_next;
|
||||
qb_map_iter_free_func iter_free;
|
||||
qb_map_notify_add_func notify_add;
|
||||
qb_map_notify_del_func notify_del;
|
||||
};
|
||||
|
||||
struct qb_map_iter {
|
||||
struct qb_map *m;
|
||||
};
|
||||
|
||||
struct qb_map_notifier {
|
||||
struct qb_list_head list;
|
||||
qb_map_notify_fn callback;
|
||||
int32_t events;
|
||||
void *user_data;
|
||||
int32_t refcount;
|
||||
};
|
||||
|
||||
|
||||
#endif /* _QB_MAP_INT_H_ */
|
||||
747
lib/ringbuffer.c
Normal file
747
lib/ringbuffer.c
Normal file
@ -0,0 +1,747 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2011 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "ringbuffer_int.h"
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbatomic.h>
|
||||
|
||||
/*
|
||||
* #define CRAZY_DEBUG_PRINTFS 1
|
||||
*/
|
||||
#ifdef CRAZY_DEBUG_PRINTFS
|
||||
#define DEBUG_PRINTF(format, args...) \
|
||||
do { \
|
||||
printf(format, ##args); \
|
||||
} while(0)
|
||||
#else
|
||||
#define DEBUG_PRINTF(format, args...)
|
||||
#endif /* CRAZY_DEBUG_PRINTFS */
|
||||
|
||||
/* the chunk header is two words
|
||||
* 1) the chunk data size
|
||||
* 2) the magic number
|
||||
*/
|
||||
#define QB_RB_CHUNK_HEADER_WORDS 2
|
||||
#define QB_RB_CHUNK_HEADER_SIZE (sizeof(uint32_t) * QB_RB_CHUNK_HEADER_WORDS)
|
||||
/*
|
||||
* margin is the gap we leave when checking to see if we have enough
|
||||
* space for a new chunk.
|
||||
* So:
|
||||
* qb_rb_space_free() >= QB_RB_CHUNK_MARGIN + new data chunk
|
||||
* The extra word size is to allow for non word sized data chunks.
|
||||
*/
|
||||
#define QB_RB_CHUNK_MARGIN (sizeof(uint32_t) * (QB_RB_CHUNK_HEADER_WORDS + 1))
|
||||
#define QB_RB_CHUNK_MAGIC 0xAAAAAAAA
|
||||
#define QB_RB_CHUNK_SIZE_GET(rb, pointer) \
|
||||
rb->shared_data[pointer]
|
||||
#define QB_RB_CHUNK_MAGIC_GET(rb, pointer) \
|
||||
rb->shared_data[(pointer + 1) % rb->shared_hdr->word_size]
|
||||
|
||||
#define QB_RB_WRITE_PT_INDEX (rb->shared_hdr->word_size)
|
||||
#define QB_RB_READ_PT_INDEX (rb->shared_hdr->word_size + 1)
|
||||
|
||||
#define idx_step(idx) \
|
||||
do { \
|
||||
if (idx > (rb->shared_hdr->word_size - 1)) { \
|
||||
idx = ((idx) % (rb->shared_hdr->word_size)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* move the write pointer to the next 32 byte boundary
|
||||
* write_pt goes in 4 bytes (sizeof(uint32_t))
|
||||
*/
|
||||
/*
|
||||
* #define USE_CACHE_LINE_ALIGNMENT 1
|
||||
*/
|
||||
#ifdef USE_CACHE_LINE_ALIGNMENT
|
||||
#define idx_cache_line_step(idx) \
|
||||
do { \
|
||||
if (idx % 8) { \
|
||||
idx += (8 - (idx % 8)); \
|
||||
} \
|
||||
if (idx > (rb->shared_hdr->word_size - 1)) { \
|
||||
idx = ((idx) % (rb->shared_hdr->word_size)); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define idx_cache_line_step(idx) \
|
||||
do { \
|
||||
if (idx > (rb->shared_hdr->word_size - 1)) { \
|
||||
idx = ((idx) % (rb->shared_hdr->word_size)); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static void qb_rb_chunk_check(struct qb_ringbuffer_s * rb, uint32_t pointer);
|
||||
|
||||
qb_ringbuffer_t *
|
||||
qb_rb_open(const char *name, size_t size, uint32_t flags,
|
||||
size_t shared_user_data_size)
|
||||
{
|
||||
struct qb_ringbuffer_s *rb;
|
||||
size_t real_size;
|
||||
size_t shared_size;
|
||||
char path[PATH_MAX];
|
||||
int32_t fd_hdr;
|
||||
int32_t fd_data;
|
||||
uint32_t file_flags = O_RDWR;
|
||||
char filename[PATH_MAX];
|
||||
int32_t error = 0;
|
||||
void *shm_addr;
|
||||
long page_size = sysconf(_SC_PAGESIZE);
|
||||
|
||||
#ifdef QB_FORCE_SHM_ALIGN
|
||||
page_size = QB_MAX(page_size, 16 * 1024);
|
||||
#endif /* QB_FORCE_SHM_ALIGN */
|
||||
real_size = QB_ROUNDUP(size, page_size);
|
||||
shared_size =
|
||||
sizeof(struct qb_ringbuffer_shared_s) + shared_user_data_size;
|
||||
|
||||
if (flags & QB_RB_FLAG_CREATE) {
|
||||
file_flags |= O_CREAT | O_TRUNC;
|
||||
}
|
||||
|
||||
rb = calloc(1, sizeof(struct qb_ringbuffer_s));
|
||||
if (rb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a shared_hdr memory segment for the header.
|
||||
*/
|
||||
snprintf(filename, PATH_MAX, "qb-%s-header", name);
|
||||
fd_hdr = qb_sys_mmap_file_open(path, filename,
|
||||
shared_size, file_flags);
|
||||
if (fd_hdr < 0) {
|
||||
error = fd_hdr;
|
||||
qb_util_log(LOG_ERR, "couldn't create file for mmap");
|
||||
goto cleanup_hdr;
|
||||
}
|
||||
|
||||
rb->shared_hdr = mmap(0,
|
||||
shared_size,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, fd_hdr, 0);
|
||||
|
||||
if (rb->shared_hdr == MAP_FAILED) {
|
||||
error = -errno;
|
||||
qb_util_log(LOG_ERR, "couldn't create mmap for header");
|
||||
goto cleanup_hdr;
|
||||
}
|
||||
|
||||
rb->flags = flags;
|
||||
|
||||
/*
|
||||
* create the semaphore
|
||||
*/
|
||||
if (flags & QB_RB_FLAG_CREATE) {
|
||||
rb->shared_data = NULL;
|
||||
/* rb->shared_hdr->word_size tracks data by ints and not bytes/chars. */
|
||||
rb->shared_hdr->word_size = real_size / sizeof(uint32_t);
|
||||
rb->shared_hdr->write_pt = 0;
|
||||
rb->shared_hdr->read_pt = 0;
|
||||
(void)strlcpy(rb->shared_hdr->hdr_path, path, PATH_MAX);
|
||||
}
|
||||
error = qb_rb_sem_create(rb, flags);
|
||||
if (error < 0) {
|
||||
qb_util_perror(LOG_ERR, "couldn't get a semaphore");
|
||||
goto cleanup_hdr;
|
||||
}
|
||||
|
||||
/* Create the shared_data memory segment for the actual ringbuffer.
|
||||
* They have to be separate.
|
||||
*/
|
||||
if (flags & QB_RB_FLAG_CREATE) {
|
||||
snprintf(filename, PATH_MAX, "qb-%s-data", name);
|
||||
fd_data = qb_sys_mmap_file_open(path,
|
||||
filename,
|
||||
real_size, file_flags);
|
||||
(void)strlcpy(rb->shared_hdr->data_path, path, PATH_MAX);
|
||||
} else {
|
||||
fd_data = qb_sys_mmap_file_open(path,
|
||||
rb->shared_hdr->data_path,
|
||||
real_size, file_flags);
|
||||
}
|
||||
if (fd_data < 0) {
|
||||
error = fd_data;
|
||||
qb_util_log(LOG_ERR, "couldn't create file for mmap");
|
||||
goto cleanup_hdr;
|
||||
}
|
||||
|
||||
qb_util_log(LOG_DEBUG,
|
||||
"shm size:%zd; real_size:%zd; rb->word_size:%d", size,
|
||||
real_size, rb->shared_hdr->word_size);
|
||||
|
||||
error = qb_sys_circular_mmap(fd_data, &shm_addr, real_size);
|
||||
rb->shared_data = shm_addr;
|
||||
if (error != 0) {
|
||||
qb_util_log(LOG_ERR, "couldn't create circular mmap on %s",
|
||||
rb->shared_hdr->data_path);
|
||||
goto cleanup_data;
|
||||
}
|
||||
|
||||
if (flags & QB_RB_FLAG_CREATE) {
|
||||
memset(rb->shared_data, 0, real_size);
|
||||
rb->shared_data[rb->shared_hdr->word_size] = 5;
|
||||
rb->shared_hdr->ref_count = 1;
|
||||
} else {
|
||||
qb_atomic_int_inc(&rb->shared_hdr->ref_count);
|
||||
}
|
||||
|
||||
close(fd_hdr);
|
||||
close(fd_data);
|
||||
return rb;
|
||||
|
||||
cleanup_data:
|
||||
close(fd_data);
|
||||
if (flags & QB_RB_FLAG_CREATE) {
|
||||
unlink(rb->shared_hdr->data_path);
|
||||
}
|
||||
|
||||
cleanup_hdr:
|
||||
if (fd_hdr >= 0) {
|
||||
close(fd_hdr);
|
||||
}
|
||||
if (rb && (flags & QB_RB_FLAG_CREATE)) {
|
||||
unlink(rb->shared_hdr->hdr_path);
|
||||
(void)rb->sem_destroy_fn(rb);
|
||||
}
|
||||
if (rb && (rb->shared_hdr != MAP_FAILED && rb->shared_hdr != NULL)) {
|
||||
munmap(rb->shared_hdr, sizeof(struct qb_ringbuffer_shared_s));
|
||||
}
|
||||
free(rb);
|
||||
errno = -error;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
qb_rb_close(struct qb_ringbuffer_s * rb)
|
||||
{
|
||||
if (rb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void)qb_atomic_int_dec_and_test(&rb->shared_hdr->ref_count);
|
||||
if (rb->flags & QB_RB_FLAG_CREATE) {
|
||||
(void)rb->sem_destroy_fn(rb);
|
||||
unlink(rb->shared_hdr->data_path);
|
||||
unlink(rb->shared_hdr->hdr_path);
|
||||
qb_util_log(LOG_DEBUG,
|
||||
"Free'ing ringbuffer: %s",
|
||||
rb->shared_hdr->hdr_path);
|
||||
} else {
|
||||
qb_util_log(LOG_DEBUG,
|
||||
"Closing ringbuffer: %s", rb->shared_hdr->hdr_path);
|
||||
}
|
||||
munmap(rb->shared_data, (rb->shared_hdr->word_size * sizeof(uint32_t)) << 1);
|
||||
munmap(rb->shared_hdr, sizeof(struct qb_ringbuffer_shared_s));
|
||||
free(rb);
|
||||
}
|
||||
|
||||
void
|
||||
qb_rb_force_close(struct qb_ringbuffer_s * rb)
|
||||
{
|
||||
if (rb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void)rb->sem_destroy_fn(rb);
|
||||
unlink(rb->shared_hdr->data_path);
|
||||
unlink(rb->shared_hdr->hdr_path);
|
||||
qb_util_log(LOG_DEBUG,
|
||||
"Force free'ing ringbuffer: %s",
|
||||
rb->shared_hdr->hdr_path);
|
||||
munmap(rb->shared_data, (rb->shared_hdr->word_size * sizeof(uint32_t)) << 1);
|
||||
munmap(rb->shared_hdr, sizeof(struct qb_ringbuffer_shared_s));
|
||||
free(rb);
|
||||
}
|
||||
|
||||
char *
|
||||
qb_rb_name_get(struct qb_ringbuffer_s * rb)
|
||||
{
|
||||
if (rb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return rb->shared_hdr->hdr_path;
|
||||
}
|
||||
|
||||
void *
|
||||
qb_rb_shared_user_data_get(struct qb_ringbuffer_s * rb)
|
||||
{
|
||||
if (rb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return rb->shared_hdr->user_data;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_rb_refcount_get(struct qb_ringbuffer_s * rb)
|
||||
{
|
||||
if (rb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return qb_atomic_int_get(&rb->shared_hdr->ref_count);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_rb_space_free(struct qb_ringbuffer_s * rb)
|
||||
{
|
||||
uint32_t write_size;
|
||||
uint32_t read_size;
|
||||
size_t space_free = 0;
|
||||
|
||||
if (rb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
write_size = rb->shared_hdr->write_pt;
|
||||
/*
|
||||
* TODO idx_cache_line_step (write_size);
|
||||
*/
|
||||
read_size = rb->shared_hdr->read_pt;
|
||||
|
||||
if (write_size > read_size) {
|
||||
space_free =
|
||||
(read_size - write_size + rb->shared_hdr->word_size) - 1;
|
||||
} else if (write_size < read_size) {
|
||||
space_free = (read_size - write_size) - 1;
|
||||
} else {
|
||||
space_free = rb->shared_hdr->word_size;
|
||||
}
|
||||
|
||||
/* word -> bytes */
|
||||
return (space_free * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_rb_space_used(struct qb_ringbuffer_s * rb)
|
||||
{
|
||||
uint32_t write_size;
|
||||
uint32_t read_size;
|
||||
size_t space_used;
|
||||
|
||||
if (rb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
write_size = rb->shared_hdr->write_pt;
|
||||
read_size = rb->shared_hdr->read_pt;
|
||||
|
||||
if (write_size > read_size) {
|
||||
space_used = write_size - read_size;
|
||||
} else if (write_size < read_size) {
|
||||
space_used =
|
||||
(write_size - read_size + rb->shared_hdr->word_size) - 1;
|
||||
} else {
|
||||
space_used = 0;
|
||||
}
|
||||
/* word -> bytes */
|
||||
return (space_used * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_rb_chunks_used(struct qb_ringbuffer_s *rb)
|
||||
{
|
||||
if (rb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return rb->sem_getvalue_fn(rb);
|
||||
}
|
||||
|
||||
void *
|
||||
qb_rb_chunk_alloc(struct qb_ringbuffer_s * rb, size_t len)
|
||||
{
|
||||
uint32_t write_pt;
|
||||
|
||||
if (rb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Reclaim data if we are over writing and we need space
|
||||
*/
|
||||
if (rb->flags & QB_RB_FLAG_OVERWRITE) {
|
||||
while (qb_rb_space_free(rb) < (len + QB_RB_CHUNK_MARGIN)) {
|
||||
qb_rb_chunk_reclaim(rb);
|
||||
}
|
||||
} else {
|
||||
if (qb_rb_space_free(rb) < (len + QB_RB_CHUNK_MARGIN)) {
|
||||
errno = EAGAIN;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
write_pt = rb->shared_hdr->write_pt;
|
||||
/*
|
||||
* insert the chunk header
|
||||
*/
|
||||
rb->shared_data[write_pt++] = 0;
|
||||
idx_step(write_pt);
|
||||
rb->shared_data[write_pt++] = QB_RB_CHUNK_MAGIC;
|
||||
idx_step(write_pt);
|
||||
|
||||
/*
|
||||
* return a pointer to the beginning of the chunk data
|
||||
*/
|
||||
return (void *)&rb->shared_data[write_pt];
|
||||
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
qb_rb_chunk_step(struct qb_ringbuffer_s * rb, uint32_t pointer)
|
||||
{
|
||||
uint32_t chunk_size = QB_RB_CHUNK_SIZE_GET(rb, pointer);
|
||||
/*
|
||||
* skip over the chunk header
|
||||
*/
|
||||
pointer += QB_RB_CHUNK_HEADER_WORDS;
|
||||
idx_step(pointer);
|
||||
|
||||
/*
|
||||
* skip over the user's data.
|
||||
*/
|
||||
pointer += (chunk_size / sizeof(uint32_t));
|
||||
/* make allowance for non-word sizes */
|
||||
if ((chunk_size % sizeof(uint32_t)) != 0) {
|
||||
pointer++;
|
||||
}
|
||||
|
||||
idx_cache_line_step(pointer);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_rb_chunk_commit(struct qb_ringbuffer_s * rb, size_t len)
|
||||
{
|
||||
uint32_t old_write_pt;
|
||||
|
||||
if (rb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* commit the magic & chunk_size
|
||||
*/
|
||||
old_write_pt = rb->shared_hdr->write_pt;
|
||||
rb->shared_data[old_write_pt] = len;
|
||||
rb->shared_data[old_write_pt + 1] = QB_RB_CHUNK_MAGIC;
|
||||
|
||||
/*
|
||||
* commit the new write pointer
|
||||
*/
|
||||
rb->shared_hdr->write_pt = qb_rb_chunk_step(rb, old_write_pt);
|
||||
|
||||
DEBUG_PRINTF("%s: read: %u, write: %u (was:%u)\n", __func__,
|
||||
rb->shared_hdr->read_pt, rb->shared_hdr->write_pt,
|
||||
old_write_pt);
|
||||
|
||||
/*
|
||||
* post the notification to the reader
|
||||
*/
|
||||
return rb->sem_post_fn(rb);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_rb_chunk_write(struct qb_ringbuffer_s * rb, const void *data, size_t len)
|
||||
{
|
||||
char *dest = qb_rb_chunk_alloc(rb, len);
|
||||
int32_t res = 0;
|
||||
|
||||
if (rb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dest == NULL) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
memcpy(dest, data, len);
|
||||
|
||||
res = qb_rb_chunk_commit(rb, len);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void
|
||||
qb_rb_chunk_reclaim(struct qb_ringbuffer_s * rb)
|
||||
{
|
||||
uint32_t old_read_pt;
|
||||
|
||||
if (rb == NULL || qb_rb_space_used(rb) == 0) {
|
||||
return;
|
||||
}
|
||||
old_read_pt = rb->shared_hdr->read_pt;
|
||||
qb_rb_chunk_check(rb, old_read_pt);
|
||||
|
||||
rb->shared_hdr->read_pt = qb_rb_chunk_step(rb, old_read_pt);
|
||||
|
||||
/*
|
||||
* clear the header
|
||||
*/
|
||||
rb->shared_data[old_read_pt] = 0;
|
||||
rb->shared_data[old_read_pt + 1] = 0;
|
||||
|
||||
DEBUG_PRINTF("%s: read: %u (was:%u), write: %u\n", __func__,
|
||||
rb->shared_hdr->read_pt, old_read_pt,
|
||||
rb->shared_hdr->write_pt);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_rb_chunk_peek(struct qb_ringbuffer_s * rb, void **data_out, int32_t timeout)
|
||||
{
|
||||
uint32_t read_pt;
|
||||
uint32_t chunk_size;
|
||||
uint32_t chunk_magic;
|
||||
int32_t res;
|
||||
|
||||
if (rb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
res = rb->sem_timedwait_fn(rb, timeout);
|
||||
if (res < 0 && res != -EIDRM) {
|
||||
if (res != -ETIMEDOUT) {
|
||||
qb_util_perror(LOG_ERR, "sem_timedwait");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
read_pt = rb->shared_hdr->read_pt;
|
||||
chunk_size = QB_RB_CHUNK_SIZE_GET(rb, read_pt);
|
||||
chunk_magic = QB_RB_CHUNK_MAGIC_GET(rb, read_pt);
|
||||
*data_out = &rb->shared_data[read_pt + QB_RB_CHUNK_HEADER_WORDS];
|
||||
|
||||
if (chunk_magic != QB_RB_CHUNK_MAGIC) {
|
||||
errno = ENOMSG;
|
||||
return 0;
|
||||
} else {
|
||||
return chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_rb_chunk_read(struct qb_ringbuffer_s * rb, void *data_out, size_t len,
|
||||
int32_t timeout)
|
||||
{
|
||||
uint32_t read_pt;
|
||||
uint32_t chunk_size;
|
||||
int32_t res = 0;
|
||||
|
||||
if (rb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (rb->sem_timedwait_fn) {
|
||||
res = rb->sem_timedwait_fn(rb, timeout);
|
||||
}
|
||||
if (res < 0 && res != -EIDRM) {
|
||||
if (res != -ETIMEDOUT) {
|
||||
qb_util_perror(LOG_ERR, "sem_timedwait");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
if (qb_rb_space_used(rb) == 0) {
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
read_pt = rb->shared_hdr->read_pt;
|
||||
qb_rb_chunk_check(rb, read_pt);
|
||||
chunk_size = QB_RB_CHUNK_SIZE_GET(rb, read_pt);
|
||||
|
||||
if (len < chunk_size) {
|
||||
qb_util_log(LOG_ERR,
|
||||
"trying to recv chunk of size %d but %d available",
|
||||
len, chunk_size);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(data_out,
|
||||
&rb->shared_data[read_pt + QB_RB_CHUNK_HEADER_WORDS],
|
||||
chunk_size);
|
||||
|
||||
qb_rb_chunk_reclaim(rb);
|
||||
|
||||
return chunk_size;
|
||||
}
|
||||
|
||||
static void
|
||||
print_header(struct qb_ringbuffer_s * rb)
|
||||
{
|
||||
printf("Ringbuffer: \n");
|
||||
if (rb->flags & QB_RB_FLAG_OVERWRITE) {
|
||||
printf(" ->OVERWRITE\n");
|
||||
} else {
|
||||
printf(" ->NORMAL\n");
|
||||
}
|
||||
printf(" ->write_pt [%d]\n", rb->shared_hdr->write_pt);
|
||||
printf(" ->read_pt [%d]\n", rb->shared_hdr->read_pt);
|
||||
printf(" ->size [%d words]\n", rb->shared_hdr->word_size);
|
||||
#ifndef S_SPLINT_S
|
||||
printf(" =>free [%zu bytes]\n", qb_rb_space_free(rb));
|
||||
printf(" =>used [%zu bytes]\n", qb_rb_space_used(rb));
|
||||
#endif /* S_SPLINT_S */
|
||||
}
|
||||
|
||||
static void
|
||||
qb_rb_chunk_check(struct qb_ringbuffer_s * rb, uint32_t pointer)
|
||||
{
|
||||
uint32_t chunk_size;
|
||||
uint32_t chunk_magic = QB_RB_CHUNK_MAGIC_GET(rb, pointer);
|
||||
|
||||
if (chunk_magic != QB_RB_CHUNK_MAGIC) {
|
||||
chunk_size = QB_RB_CHUNK_SIZE_GET(rb, pointer);
|
||||
printf("size: %x\n", chunk_size);
|
||||
printf("magic: %x\n", chunk_magic);
|
||||
print_header(rb);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t
|
||||
qb_rb_write_to_file(struct qb_ringbuffer_s * rb, int32_t fd)
|
||||
{
|
||||
ssize_t result;
|
||||
ssize_t written_size = 0;
|
||||
|
||||
if (rb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
print_header(rb);
|
||||
|
||||
result = write(fd, &rb->shared_hdr->word_size, sizeof(uint32_t));
|
||||
if (result != sizeof(uint32_t)) {
|
||||
return -errno;
|
||||
}
|
||||
written_size += result;
|
||||
|
||||
result = write(fd, rb->shared_data,
|
||||
rb->shared_hdr->word_size * sizeof(uint32_t));
|
||||
if (result != rb->shared_hdr->word_size * sizeof(uint32_t)) {
|
||||
return -errno;
|
||||
}
|
||||
written_size += result;
|
||||
|
||||
/*
|
||||
* store the read & write pointers
|
||||
*/
|
||||
result = write(fd, (void *)&rb->shared_hdr->write_pt, sizeof(uint32_t));
|
||||
if (result != sizeof(uint32_t)) {
|
||||
return -errno;
|
||||
}
|
||||
written_size += result;
|
||||
result = write(fd, (void *)&rb->shared_hdr->read_pt, sizeof(uint32_t));
|
||||
if (result != sizeof(uint32_t)) {
|
||||
return -errno;
|
||||
}
|
||||
written_size += result;
|
||||
|
||||
qb_util_log(LOG_DEBUG, " writing total of: %zd\n", written_size);
|
||||
|
||||
return written_size;
|
||||
}
|
||||
|
||||
qb_ringbuffer_t *
|
||||
qb_rb_create_from_file(int32_t fd, uint32_t flags)
|
||||
{
|
||||
ssize_t n_read;
|
||||
size_t n_required;
|
||||
size_t total_read = 0;
|
||||
uint32_t read_pt;
|
||||
uint32_t write_pt;
|
||||
struct qb_ringbuffer_s *rb;
|
||||
|
||||
if (fd < 0) {
|
||||
return NULL;
|
||||
}
|
||||
rb = calloc(1, sizeof(struct qb_ringbuffer_s));
|
||||
if (rb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
rb->shared_hdr = calloc(1, sizeof(struct qb_ringbuffer_shared_s));
|
||||
if (rb->shared_hdr == NULL) {
|
||||
goto cleanup_fail2;
|
||||
}
|
||||
|
||||
rb->flags = flags;
|
||||
|
||||
n_required = sizeof(uint32_t);
|
||||
n_read = read(fd, &rb->shared_hdr->word_size, n_required);
|
||||
if (n_read != n_required) {
|
||||
qb_util_perror(LOG_ERR, "Unable to read blackbox file header");
|
||||
goto cleanup_fail;
|
||||
}
|
||||
total_read += n_read;
|
||||
|
||||
n_required = (rb->shared_hdr->word_size * sizeof(uint32_t));
|
||||
|
||||
if ((rb->shared_data = malloc(n_required)) == NULL) {
|
||||
qb_util_perror(LOG_ERR, "exhausted virtual memory");
|
||||
goto cleanup_fail;
|
||||
}
|
||||
n_read = read(fd, rb->shared_data, n_required);
|
||||
if (n_read < 0) {
|
||||
qb_util_perror(LOG_ERR, "Unable to read blackbox file data");
|
||||
goto cleanup_fail;
|
||||
}
|
||||
total_read += n_read;
|
||||
|
||||
if (n_read != n_required) {
|
||||
qb_util_log(LOG_WARNING, "read %zd bytes, but expected %zu",
|
||||
n_read, n_required);
|
||||
goto cleanup_fail;
|
||||
}
|
||||
|
||||
n_read = read(fd, &write_pt, sizeof(uint32_t));
|
||||
assert(n_read == sizeof(uint32_t));
|
||||
rb->shared_hdr->write_pt = write_pt;
|
||||
total_read += n_read;
|
||||
|
||||
n_read = read(fd, &read_pt, sizeof(uint32_t));
|
||||
assert(n_read == sizeof(uint32_t));
|
||||
rb->shared_hdr->read_pt = read_pt;
|
||||
total_read += n_read;
|
||||
|
||||
qb_util_log(LOG_DEBUG, "read total of: %zd", total_read);
|
||||
print_header(rb);
|
||||
|
||||
return rb;
|
||||
|
||||
cleanup_fail:
|
||||
free(rb->shared_hdr);
|
||||
cleanup_fail2:
|
||||
free(rb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t
|
||||
qb_rb_chown(struct qb_ringbuffer_s * rb, uid_t owner, gid_t group)
|
||||
{
|
||||
int32_t res;
|
||||
|
||||
if (rb == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
res = chown(rb->shared_hdr->data_path, owner, group);
|
||||
if (res < 0) {
|
||||
return -errno;
|
||||
}
|
||||
res = chown(rb->shared_hdr->hdr_path, owner, group);
|
||||
if (res < 0) {
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
273
lib/ringbuffer_helper.c
Normal file
273
lib/ringbuffer_helper.c
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "ringbuffer_int.h"
|
||||
#include <qb/qbdefs.h>
|
||||
|
||||
static int32_t
|
||||
my_posix_sem_timedwait(qb_ringbuffer_t * rb, int32_t ms_timeout)
|
||||
{
|
||||
struct timespec ts_timeout;
|
||||
int32_t res;
|
||||
|
||||
if (ms_timeout > 0) {
|
||||
qb_util_timespec_from_epoch_get(&ts_timeout);
|
||||
qb_timespec_add_ms(&ts_timeout, ms_timeout);
|
||||
}
|
||||
|
||||
sem_wait_again:
|
||||
if (ms_timeout > 0) {
|
||||
res = sem_timedwait(&rb->shared_hdr->posix_sem, &ts_timeout);
|
||||
} else if (ms_timeout == 0) {
|
||||
res = sem_trywait(&rb->shared_hdr->posix_sem);
|
||||
} else {
|
||||
res = sem_wait(&rb->shared_hdr->posix_sem);
|
||||
}
|
||||
if (res == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
goto sem_wait_again;
|
||||
break;
|
||||
case EAGAIN:
|
||||
res = -ETIMEDOUT;
|
||||
break;
|
||||
case ETIMEDOUT:
|
||||
res = -errno;
|
||||
break;
|
||||
default:
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "error waiting for semaphore");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_posix_sem_post(qb_ringbuffer_t * rb)
|
||||
{
|
||||
if (sem_post(&rb->shared_hdr->posix_sem) < 0) {
|
||||
return -errno;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
my_posix_getvalue_fn(struct qb_ringbuffer_s *rb)
|
||||
{
|
||||
int val;
|
||||
if (sem_getvalue(&rb->shared_hdr->posix_sem, &val) < 0) {
|
||||
return -errno;
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_posix_sem_destroy(qb_ringbuffer_t * rb)
|
||||
{
|
||||
if (sem_destroy(&rb->shared_hdr->posix_sem) == -1) {
|
||||
return -errno;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_posix_sem_create(struct qb_ringbuffer_s *rb, uint32_t flags)
|
||||
{
|
||||
int32_t pshared = 0;
|
||||
if (flags & QB_RB_FLAG_SHARED_PROCESS) {
|
||||
if ((flags & QB_RB_FLAG_CREATE) == 0) {
|
||||
return 0;
|
||||
}
|
||||
pshared = 1;
|
||||
}
|
||||
if (sem_init(&rb->shared_hdr->posix_sem, pshared, 0) == -1) {
|
||||
return -errno;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_POSIX_SHARED_SEMAPHORE
|
||||
static int32_t
|
||||
my_sysv_sem_timedwait(qb_ringbuffer_t * rb, int32_t ms_timeout)
|
||||
{
|
||||
struct sembuf sops[1];
|
||||
int32_t res = 0;
|
||||
#ifndef QB_FREEBSD_GE_8
|
||||
struct timespec ts_timeout;
|
||||
struct timespec *ts_pt;
|
||||
|
||||
if (ms_timeout >= 0) {
|
||||
/*
|
||||
* Note: sem_timedwait takes an absolute time where as semtimedop
|
||||
* takes a relative time.
|
||||
*/
|
||||
ts_timeout.tv_sec = 0;
|
||||
ts_timeout.tv_nsec = 0;
|
||||
qb_timespec_add_ms(&ts_timeout, ms_timeout);
|
||||
ts_pt = &ts_timeout;
|
||||
} else {
|
||||
ts_pt = NULL;
|
||||
}
|
||||
#endif /* bsd */
|
||||
|
||||
/*
|
||||
* wait for sem post.
|
||||
*/
|
||||
sops[0].sem_num = 0;
|
||||
sops[0].sem_op = -1;
|
||||
#ifdef QB_FREEBSD_GE_8
|
||||
sops[0].sem_flg = IPC_NOWAIT;
|
||||
#else
|
||||
sops[0].sem_flg = 0;
|
||||
#endif /* bsd */
|
||||
|
||||
semop_again:
|
||||
#ifdef QB_FREEBSD_GE_8
|
||||
if (semop(rb->sem_id, sops, 1) == -1)
|
||||
#else
|
||||
if (semtimedop(rb->sem_id, sops, 1, ts_pt) == -1)
|
||||
#endif
|
||||
{
|
||||
if (errno == EINTR) {
|
||||
goto semop_again;
|
||||
} else if (errno == EAGAIN) {
|
||||
/* make consistent with sem_timedwait */
|
||||
res = -ETIMEDOUT;
|
||||
} else {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "error waiting for semaphore");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_sysv_sem_post(qb_ringbuffer_t * rb)
|
||||
{
|
||||
struct sembuf sops[1];
|
||||
|
||||
if ((rb->flags & QB_RB_FLAG_SHARED_PROCESS) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sops[0].sem_num = 0;
|
||||
sops[0].sem_op = 1;
|
||||
sops[0].sem_flg = 0;
|
||||
|
||||
semop_again:
|
||||
if (semop(rb->sem_id, sops, 1) == -1) {
|
||||
if (errno == EINTR) {
|
||||
goto semop_again;
|
||||
} else {
|
||||
qb_util_perror(LOG_ERR,
|
||||
"could not increment semaphore");
|
||||
}
|
||||
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
my_sysv_getvalue_fn(struct qb_ringbuffer_s *rb)
|
||||
{
|
||||
ssize_t res = semctl(rb->sem_id, 0, GETVAL, 0);
|
||||
if (res == -1) {
|
||||
return -errno;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_sysv_sem_destroy(qb_ringbuffer_t * rb)
|
||||
{
|
||||
if (semctl(rb->sem_id, 0, IPC_RMID, 0) == -1) {
|
||||
return -errno;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_sysv_sem_create(qb_ringbuffer_t * rb, uint32_t flags)
|
||||
{
|
||||
union semun options;
|
||||
int32_t res;
|
||||
key_t sem_key;
|
||||
|
||||
sem_key = ftok(rb->shared_hdr->hdr_path, (rb->shared_hdr->word_size + 1));
|
||||
|
||||
if (sem_key == -1) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "couldn't get a sem id");
|
||||
return res;
|
||||
}
|
||||
|
||||
if (flags & QB_RB_FLAG_CREATE) {
|
||||
rb->sem_id = semget(sem_key, 1, IPC_CREAT | IPC_EXCL | 0600);
|
||||
if (rb->sem_id == -1) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "couldn't create a semaphore");
|
||||
return res;
|
||||
}
|
||||
options.val = 0;
|
||||
res = semctl(rb->sem_id, 0, SETVAL, options);
|
||||
} else {
|
||||
rb->sem_id = semget(sem_key, 0, 0600);
|
||||
if (rb->sem_id == -1) {
|
||||
res = -errno;
|
||||
qb_util_perror(LOG_ERR, "couldn't get a sem id");
|
||||
return res;
|
||||
}
|
||||
res = 0;
|
||||
}
|
||||
qb_util_log(LOG_DEBUG, "sem key:%d, id:%d, value:%d",
|
||||
(int)sem_key, rb->sem_id, semctl(rb->sem_id, 0, GETVAL, 0));
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif /* NOT HAVE_POSIX_SHARED_SEMAPHORE */
|
||||
|
||||
int32_t
|
||||
qb_rb_sem_create(struct qb_ringbuffer_s * rb, uint32_t flags)
|
||||
{
|
||||
#ifndef HAVE_POSIX_SHARED_SEMAPHORE
|
||||
if (rb->flags & QB_RB_FLAG_SHARED_PROCESS) {
|
||||
rb->sem_timedwait_fn = my_sysv_sem_timedwait;
|
||||
rb->sem_post_fn = my_sysv_sem_post;
|
||||
rb->sem_getvalue_fn = my_sysv_getvalue_fn;
|
||||
rb->sem_destroy_fn = my_sysv_sem_destroy;
|
||||
return my_sysv_sem_create(rb, flags);
|
||||
} else
|
||||
#endif /* NOT HAVE_POSIX_SHARED_SEMAPHORE */
|
||||
{
|
||||
rb->sem_timedwait_fn = my_posix_sem_timedwait;
|
||||
rb->sem_post_fn = my_posix_sem_post;
|
||||
rb->sem_getvalue_fn = my_posix_getvalue_fn;
|
||||
rb->sem_destroy_fn = my_posix_sem_destroy;
|
||||
return my_posix_sem_create(rb, flags);
|
||||
}
|
||||
}
|
||||
86
lib/ringbuffer_int.h
Normal file
86
lib/ringbuffer_int.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _RINGBUFFER_H_
|
||||
#define _RINGBUFFER_H_
|
||||
|
||||
#include "os_base.h"
|
||||
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif /* HAVE_SYS_MMAN_H */
|
||||
#ifdef HAVE_SYS_SEM_H
|
||||
#include <sys/sem.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IPC_H
|
||||
#include <sys/ipc.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include "util_int.h"
|
||||
#include <qb/qbutil.h>
|
||||
#include <qb/qbrb.h>
|
||||
|
||||
struct qb_ringbuffer_s;
|
||||
|
||||
int32_t qb_rb_sem_create(struct qb_ringbuffer_s *rb, uint32_t flags);
|
||||
typedef int32_t(*qb_rb_sem_post_fn_t) (struct qb_ringbuffer_s * rb);
|
||||
typedef ssize_t(*qb_rb_sem_getvalue_fn_t) (struct qb_ringbuffer_s * rb);
|
||||
typedef int32_t(*qb_rb_sem_timedwait_fn_t) (struct qb_ringbuffer_s * rb,
|
||||
int32_t ms_timeout);
|
||||
typedef int32_t(*qb_rb_sem_destroy_fn_t) (struct qb_ringbuffer_s * rb);
|
||||
|
||||
struct qb_ringbuffer_shared_s {
|
||||
volatile uint32_t write_pt;
|
||||
volatile uint32_t read_pt;
|
||||
uint32_t word_size;
|
||||
char hdr_path[PATH_MAX];
|
||||
char data_path[PATH_MAX];
|
||||
int32_t ref_count;
|
||||
sem_t posix_sem;
|
||||
char user_data[1];
|
||||
};
|
||||
|
||||
struct qb_ringbuffer_s {
|
||||
uint32_t flags;
|
||||
int32_t sem_id;
|
||||
struct qb_ringbuffer_shared_s *shared_hdr;
|
||||
uint32_t *shared_data;
|
||||
|
||||
qb_rb_sem_post_fn_t sem_post_fn;
|
||||
qb_rb_sem_getvalue_fn_t sem_getvalue_fn;
|
||||
qb_rb_sem_timedwait_fn_t sem_timedwait_fn;
|
||||
qb_rb_sem_destroy_fn_t sem_destroy_fn;
|
||||
};
|
||||
|
||||
|
||||
void qb_rb_force_close(qb_ringbuffer_t * rb);
|
||||
|
||||
#if defined(_SEM_SEMUN_UNDEFINED)
|
||||
union semun {
|
||||
int32_t val;
|
||||
struct semid_ds *buf;
|
||||
unsigned short int *array;
|
||||
struct seminfo *__buf;
|
||||
};
|
||||
#endif /* _SEM_SEMUN_UNDEFINED */
|
||||
|
||||
#endif /* _RINGBUFFER_H_ */
|
||||
564
lib/skiplist.c
Normal file
564
lib/skiplist.c
Normal file
@ -0,0 +1,564 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* This file is part of libqb.
|
||||
*
|
||||
* libqb 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.
|
||||
*
|
||||
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <os_base.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbmap.h>
|
||||
#include "map_int.h"
|
||||
|
||||
#define SKIPLIST_LEVEL_MAX 8
|
||||
#define SKIPLIST_LEVEL_MIN 0
|
||||
/* The amount of possible levels */
|
||||
#define SKIPLIST_LEVEL_COUNT (SKIPLIST_LEVEL_MAX - SKIPLIST_LEVEL_MIN + 1)
|
||||
|
||||
struct skiplist_iter {
|
||||
struct qb_map_iter i;
|
||||
struct skiplist_node *n;
|
||||
};
|
||||
|
||||
struct skiplist_node {
|
||||
const char *key;
|
||||
void *value;
|
||||
int8_t level;
|
||||
uint32_t refcount;
|
||||
struct qb_list_head notifier_head;
|
||||
|
||||
/* An array of @level + 1 node pointers */
|
||||
struct skiplist_node **forward;
|
||||
};
|
||||
|
||||
struct skiplist {
|
||||
struct qb_map map;
|
||||
|
||||
size_t length;
|
||||
int8_t level;
|
||||
struct skiplist_node *header;
|
||||
};
|
||||
|
||||
/* An array of nodes that need to be updated after an insert or delete operation
|
||||
*/
|
||||
typedef struct skiplist_node *skiplist_update_t[SKIPLIST_LEVEL_COUNT];
|
||||
|
||||
static int8_t
|
||||
skiplist_level_generate(void)
|
||||
{
|
||||
/* This constant is found by 1 / P, where P = 0.25. */
|
||||
enum { P_INVERSE = 4 };
|
||||
|
||||
/* The original algorithm's random number is in the range [0, 1), so
|
||||
* max M = 1. Its ceiling C = M * P = 1 * P = P.
|
||||
*
|
||||
* Our random number is in the range [0, UINT16_MAX], so M = UINT16_MAX. Therefore,
|
||||
* C = UINT16_MAX * P = UINT16_MAX / P_INVERSE.
|
||||
*/
|
||||
enum { P_CEIL = UINT16_MAX / P_INVERSE };
|
||||
int8_t level = SKIPLIST_LEVEL_MIN;
|
||||
|
||||
while ((uint16_t) (random()) < P_CEIL)
|
||||
level++;
|
||||
|
||||
if (level < SKIPLIST_LEVEL_MAX)
|
||||
return level;
|
||||
|
||||
return SKIPLIST_LEVEL_MAX;
|
||||
}
|
||||
|
||||
static struct skiplist_node *
|
||||
skiplist_node_next(const struct skiplist_node *node)
|
||||
{
|
||||
const struct skiplist_node *n = node;
|
||||
do {
|
||||
n = n->forward[SKIPLIST_LEVEL_MIN];
|
||||
} while (n && n->refcount == 0);
|
||||
return (struct skiplist_node *)n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new level @level node with value @value. The node should eventually
|
||||
* be destroyed with @skiplist_node_destroy.
|
||||
*
|
||||
* return: a new node on success and NULL otherwise.
|
||||
*/
|
||||
static struct skiplist_node *
|
||||
skiplist_node_new(const int8_t level, const char *key, const void *value)
|
||||
{
|
||||
struct skiplist_node *new_node = (struct skiplist_node *)
|
||||
(malloc(sizeof(struct skiplist_node)));
|
||||
|
||||
if (!new_node)
|
||||
return NULL;
|
||||
|
||||
new_node->value = (void *)value;
|
||||
new_node->key = key;
|
||||
new_node->level = level;
|
||||
new_node->refcount = 1;
|
||||
qb_list_init(&new_node->notifier_head);
|
||||
|
||||
/* A level 0 node still needs to hold 1 forward pointer, etc. */
|
||||
new_node->forward = (struct skiplist_node **)
|
||||
(calloc(level + 1, sizeof(struct skiplist_node *)));
|
||||
|
||||
if (new_node->forward == NULL) {
|
||||
free(new_node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new_node;
|
||||
}
|
||||
|
||||
static struct skiplist_node *
|
||||
skiplist_header_node_new(void)
|
||||
{
|
||||
return skiplist_node_new(SKIPLIST_LEVEL_MAX, NULL, NULL);
|
||||
}
|
||||
|
||||
/* An operation to perform after comparing a user value or search with a
|
||||
* node's value
|
||||
*/
|
||||
typedef enum {
|
||||
OP_GOTO_NEXT_LEVEL,
|
||||
OP_GOTO_NEXT_NODE,
|
||||
OP_FINISH,
|
||||
} op_t;
|
||||
|
||||
static op_t
|
||||
op_search(const struct skiplist *list,
|
||||
const struct skiplist_node *fwd_node, const void *search)
|
||||
{
|
||||
int32_t cmp;
|
||||
|
||||
if (!fwd_node)
|
||||
return OP_GOTO_NEXT_LEVEL;
|
||||
|
||||
cmp = strcmp(fwd_node->key, search);
|
||||
if (cmp < 0) {
|
||||
return OP_GOTO_NEXT_NODE;
|
||||
} else if (cmp == 0) {
|
||||
return OP_FINISH;
|
||||
}
|
||||
|
||||
return OP_GOTO_NEXT_LEVEL;
|
||||
}
|
||||
|
||||
static struct skiplist_node *
|
||||
skiplist_lookup(struct skiplist *list, const char *key)
|
||||
{
|
||||
struct skiplist_node *cur_node = list->header;
|
||||
int8_t level = list->level;
|
||||
|
||||
while (level >= SKIPLIST_LEVEL_MIN) {
|
||||
struct skiplist_node *fwd_node = cur_node->forward[level];
|
||||
|
||||
switch (op_search(list, fwd_node, key)) {
|
||||
case OP_FINISH:
|
||||
return fwd_node;
|
||||
case OP_GOTO_NEXT_NODE:
|
||||
cur_node = fwd_node;
|
||||
break;
|
||||
case OP_GOTO_NEXT_LEVEL:
|
||||
level--;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
skiplist_notify(struct skiplist *l, struct skiplist_node *n,
|
||||
uint32_t event, char *key, void *old_value, void *value)
|
||||
{
|
||||
struct qb_list_head *list;
|
||||
struct qb_map_notifier *tn;
|
||||
|
||||
/* node callbacks
|
||||
*/
|
||||
for (list = n->notifier_head.next;
|
||||
list != &n->notifier_head; list = list->next) {
|
||||
tn = qb_list_entry(list, struct qb_map_notifier, list);
|
||||
|
||||
if (tn->events & event) {
|
||||
tn->callback(event, key, old_value, value,
|
||||
tn->user_data);
|
||||
}
|
||||
}
|
||||
/* global callbacks
|
||||
*/
|
||||
for (list = l->header->notifier_head.next;
|
||||
list != &l->header->notifier_head; list = list->next) {
|
||||
tn = qb_list_entry(list, struct qb_map_notifier, list);
|
||||
|
||||
if (tn->events & event) {
|
||||
tn->callback(event, key, old_value, value,
|
||||
tn->user_data);
|
||||
}
|
||||
if (((event & QB_MAP_NOTIFY_DELETED) ||
|
||||
(event & QB_MAP_NOTIFY_REPLACED)) &&
|
||||
(tn->events & QB_MAP_NOTIFY_FREE)) {
|
||||
tn->callback(QB_MAP_NOTIFY_FREE, (char *)key,
|
||||
old_value, value, tn->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
skiplist_node_destroy(struct skiplist_node *node, struct skiplist *list)
|
||||
{
|
||||
skiplist_notify(list, node,
|
||||
QB_MAP_NOTIFY_DELETED,
|
||||
(char *)node->key, node->value, NULL);
|
||||
|
||||
free(node->forward);
|
||||
free(node);
|
||||
}
|
||||
|
||||
static void
|
||||
skiplist_node_deref(struct skiplist_node *node, struct skiplist *list)
|
||||
{
|
||||
node->refcount--;
|
||||
if (node->refcount == 0) {
|
||||
skiplist_node_destroy(node, list);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
skiplist_notify_add(qb_map_t * m, const char *key,
|
||||
qb_map_notify_fn fn, int32_t events, void *user_data)
|
||||
{
|
||||
struct skiplist *t = (struct skiplist *)m;
|
||||
struct qb_map_notifier *f;
|
||||
struct skiplist_node *n;
|
||||
struct qb_list_head *list;
|
||||
int add_to_tail = QB_FALSE;
|
||||
|
||||
if (key) {
|
||||
n = skiplist_lookup(t, key);
|
||||
} else {
|
||||
n = t->header;
|
||||
}
|
||||
if (events & QB_MAP_NOTIFY_FREE) {
|
||||
add_to_tail = QB_TRUE;
|
||||
}
|
||||
if (n) {
|
||||
for (list = n->notifier_head.next;
|
||||
list != &n->notifier_head; list = list->next) {
|
||||
f = qb_list_entry(list, struct qb_map_notifier, list);
|
||||
|
||||
if (events & QB_MAP_NOTIFY_FREE &&
|
||||
f->events == events) {
|
||||
/* only one free notifier */
|
||||
return -EEXIST;
|
||||
}
|
||||
if (f->events == events &&
|
||||
f->callback == fn &&
|
||||
f->user_data == user_data) {
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
f = malloc(sizeof(struct qb_map_notifier));
|
||||
if (f == NULL) {
|
||||
return -errno;
|
||||
}
|
||||
f->events = events;
|
||||
f->user_data = user_data;
|
||||
f->callback = fn;
|
||||
qb_list_init(&f->list);
|
||||
if (add_to_tail) {
|
||||
qb_list_add_tail(&f->list, &n->notifier_head);
|
||||
} else {
|
||||
qb_list_add(&f->list, &n->notifier_head);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
skiplist_notify_del(qb_map_t * m, const char *key,
|
||||
qb_map_notify_fn fn, int32_t events,
|
||||
int32_t cmp_userdata, void *user_data)
|
||||
{
|
||||
struct skiplist *t = (struct skiplist *)m;
|
||||
struct skiplist_node *n;
|
||||
struct qb_map_notifier *f;
|
||||
struct qb_list_head *head = NULL;
|
||||
struct qb_list_head *list;
|
||||
struct qb_list_head *next;
|
||||
int32_t found = QB_FALSE;
|
||||
|
||||
if (key) {
|
||||
n = skiplist_lookup(t, key);
|
||||
if (n) {
|
||||
head = &n->notifier_head;
|
||||
}
|
||||
} else {
|
||||
head = &t->header->notifier_head;
|
||||
}
|
||||
if (head == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
for (list = head->next;
|
||||
list != head; list = next) {
|
||||
f = qb_list_entry(list, struct qb_map_notifier, list);
|
||||
next = list->next;
|
||||
|
||||
if (f->events == events && f->callback == fn) {
|
||||
if (cmp_userdata && (f->user_data == user_data)) {
|
||||
found = QB_TRUE;
|
||||
qb_list_del(&f->list);
|
||||
free(f);
|
||||
} else if (!cmp_userdata) {
|
||||
found = QB_TRUE;
|
||||
qb_list_del(&f->list);
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return 0;
|
||||
} else {
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
skiplist_destroy(struct qb_map *map)
|
||||
{
|
||||
struct skiplist *list = (struct skiplist *)map;
|
||||
struct skiplist_node *cur_node;
|
||||
struct skiplist_node *fwd_node;
|
||||
|
||||
for (cur_node = skiplist_node_next(list->header);
|
||||
cur_node; cur_node = fwd_node) {
|
||||
fwd_node = skiplist_node_next(cur_node);
|
||||
skiplist_node_destroy(cur_node, list);
|
||||
}
|
||||
skiplist_node_destroy(list->header, list);
|
||||
free(list);
|
||||
}
|
||||
|
||||
static void
|
||||
skiplist_put(struct qb_map *map, const char *key, const void *value)
|
||||
{
|
||||
struct skiplist *list = (struct skiplist *)map;
|
||||
struct skiplist_node *new_node;
|
||||
int8_t level = list->level;
|
||||
skiplist_update_t update;
|
||||
int8_t update_level;
|
||||
int8_t new_node_level;
|
||||
struct skiplist_node *cur_node = list->header;
|
||||
char *old_k;
|
||||
char *old_v;
|
||||
|
||||
while ((update_level = level) >= SKIPLIST_LEVEL_MIN) {
|
||||
struct skiplist_node *fwd_node = cur_node->forward[level];
|
||||
|
||||
switch (op_search(list, fwd_node, key)) {
|
||||
case OP_FINISH:
|
||||
old_k = (char *)fwd_node->key;
|
||||
old_v = (char *)fwd_node->value;
|
||||
fwd_node->value = (void *)value;
|
||||
fwd_node->key = (void *)key;
|
||||
skiplist_notify(list, fwd_node,
|
||||
QB_MAP_NOTIFY_REPLACED,
|
||||
old_k, old_v, fwd_node->value);
|
||||
return;
|
||||
|
||||
case OP_GOTO_NEXT_NODE:
|
||||
cur_node = fwd_node;
|
||||
break;
|
||||
case OP_GOTO_NEXT_LEVEL:
|
||||
level--;
|
||||
}
|
||||
|
||||
update[update_level] = cur_node;
|
||||
}
|
||||
|
||||
new_node_level = skiplist_level_generate();
|
||||
|
||||
if (new_node_level > list->level) {
|
||||
for (level = list->level + 1; level <= new_node_level; level++)
|
||||
update[level] = list->header;
|
||||
|
||||
list->level = new_node_level;
|
||||
}
|
||||
|
||||
new_node = skiplist_node_new(new_node_level, key, value);
|
||||
|
||||
assert(new_node != NULL);
|
||||
skiplist_notify(list, new_node,
|
||||
QB_MAP_NOTIFY_INSERTED,
|
||||
(char*)new_node->key, NULL, new_node->value);
|
||||
|
||||
/* Drop @new_node into @list. */
|
||||
for (level = SKIPLIST_LEVEL_MIN; level <= new_node_level; level++) {
|
||||
new_node->forward[level] = update[level]->forward[level];
|
||||
update[level]->forward[level] = new_node;
|
||||
}
|
||||
|
||||
list->length++;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
skiplist_rm(struct qb_map *map, const char *key)
|
||||
{
|
||||
struct skiplist *list = (struct skiplist *)map;
|
||||
struct skiplist_node *found_node;
|
||||
struct skiplist_node *cur_node = list->header;
|
||||
int8_t level = list->level;
|
||||
int8_t update_level;
|
||||
skiplist_update_t update;
|
||||
|
||||
while ((update_level = level) >= SKIPLIST_LEVEL_MIN) {
|
||||
struct skiplist_node *fwd_node = cur_node->forward[level];
|
||||
|
||||
switch (op_search(list, fwd_node, key)) {
|
||||
case OP_GOTO_NEXT_NODE:
|
||||
cur_node = fwd_node;
|
||||
break;
|
||||
case OP_GOTO_NEXT_LEVEL:
|
||||
default:
|
||||
level--;
|
||||
break;
|
||||
}
|
||||
|
||||
update[update_level] = cur_node;
|
||||
}
|
||||
|
||||
/* The immediate forward node should be the matching node... */
|
||||
found_node = skiplist_node_next(cur_node);
|
||||
|
||||
/* ...unless we're at the end of the list or the value doesn't exist. */
|
||||
if (!found_node || strcmp(found_node->key, key) != 0) {
|
||||
return QB_FALSE;
|
||||
}
|
||||
|
||||
/* Splice found_node out of list. */
|
||||
for (level = SKIPLIST_LEVEL_MIN; level <= list->level; level++)
|
||||
if (update[level]->forward[level] == found_node)
|
||||
update[level]->forward[level] =
|
||||
found_node->forward[level];
|
||||
|
||||
skiplist_node_deref(found_node, list);
|
||||
|
||||
/* Remove unused levels from @list -- stop removing levels as soon as a
|
||||
* used level is found. Unused levels can occur if @found_node had the
|
||||
* highest level.
|
||||
*/
|
||||
for (level = list->level; level >= SKIPLIST_LEVEL_MIN; level--) {
|
||||
if (list->header->forward[level])
|
||||
break;
|
||||
|
||||
list->level--;
|
||||
}
|
||||
|
||||
list->length--;
|
||||
|
||||
return QB_TRUE;
|
||||
}
|
||||
|
||||
static void *
|
||||
skiplist_get(struct qb_map *map, const char *key)
|
||||
{
|
||||
struct skiplist *list = (struct skiplist *)map;
|
||||
struct skiplist_node *n = skiplist_lookup(list, key);
|
||||
if (n) {
|
||||
return n->value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static qb_map_iter_t *
|
||||
skiplist_iter_create(struct qb_map *map, const char *prefix)
|
||||
{
|
||||
struct skiplist_iter *i = malloc(sizeof(struct skiplist_iter));
|
||||
struct skiplist *list = (struct skiplist *)map;
|
||||
if (i == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
i->i.m = map;
|
||||
i->n = list->header;
|
||||
i->n->refcount++;
|
||||
return (qb_map_iter_t *) i;
|
||||
}
|
||||
|
||||
static const char *
|
||||
skiplist_iter_next(qb_map_iter_t * i, void **value)
|
||||
{
|
||||
struct skiplist_iter *si = (struct skiplist_iter *)i;
|
||||
struct skiplist_node *p = si->n;
|
||||
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
si->n = skiplist_node_next(p);
|
||||
if (si->n == NULL) {
|
||||
skiplist_node_deref(p, (struct skiplist *)i->m);
|
||||
return NULL;
|
||||
}
|
||||
si->n->refcount++;
|
||||
skiplist_node_deref(p, (struct skiplist *)i->m);
|
||||
*value = si->n->value;
|
||||
return si->n->key;
|
||||
}
|
||||
|
||||
static void
|
||||
skiplist_iter_free(qb_map_iter_t * i)
|
||||
{
|
||||
free(i);
|
||||
}
|
||||
|
||||
static size_t
|
||||
skiplist_count_get(struct qb_map *map)
|
||||
{
|
||||
struct skiplist *list = (struct skiplist *)map;
|
||||
return list->length;
|
||||
}
|
||||
|
||||
qb_map_t *
|
||||
qb_skiplist_create(void)
|
||||
{
|
||||
struct skiplist *sl = malloc(sizeof(struct skiplist));
|
||||
if (sl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
sl->map.put = skiplist_put;
|
||||
sl->map.get = skiplist_get;
|
||||
sl->map.rm = skiplist_rm;
|
||||
sl->map.count_get = skiplist_count_get;
|
||||
sl->map.iter_create = skiplist_iter_create;
|
||||
sl->map.iter_next = skiplist_iter_next;
|
||||
sl->map.iter_free = skiplist_iter_free;
|
||||
sl->map.destroy = skiplist_destroy;
|
||||
sl->map.notify_add = skiplist_notify_add;
|
||||
sl->map.notify_del = skiplist_notify_del;
|
||||
sl->level = SKIPLIST_LEVEL_MIN;
|
||||
sl->length = 0;
|
||||
sl->header = skiplist_header_node_new();
|
||||
|
||||
return (qb_map_t *) sl;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user