The GNU C Library project is a consensus-based community-driven project.
Consensus: General agreement, characterized by the absence of sustained opposition to substantial issues by an important part of the concerned interests and by a process that involves seeking to take into account the views of all parties concerned and to reconcile any conflicting arguments. Consensus need not imply unanimity. Although it is necessary for developer work to progress speedily, sufficient time is required for the discussion, negotiation and resolution of significant technical disagreements. Developers need to ensure discipline with respect to release schedules in order to avoid long review times. Similarly, to avoid re-discussion, developers have the responsibility of ensuring that their contribution takes into account all interests concerned, and that this standpoint is made clear at an early stage of the work rather than, for example, in a final patch or commit. (Language based loosely on the ISO definition).
1. How do I build consensus?
You build consensus in 5 very difficult steps:
- Define or reiterate success criteria.
- Identify a technical problem.
- Look for resolution on a singular technical problem, summarize participant positions, and eventually move it to a "resolved" state. Keep in mind consensus need not be unanimous and record complaints and concerns for future use.
- Summarize the "resolved" list, and summarize the remaining identified technical problems.
The first step is to define success. Defining when you stop is important because continuing a technical discussion takes time and effort, and without a success criteria it has no end. Examples of success criteria include:
- A decision to take ownership of the malloc algorithm and implementation.
- A decision that the TLS block should not be taken from the thread stack.
- Lazy TLS allocation cannot be done safely from signal handlers and should happen upfront in dlopen.
- The tunables framework should use one environment variable to express all library tunables.
Do not start a discussion if you don't have a well written success criteria.
Identifying, resolving and summarizing are the next key parts of reaching consensus. There is no easy way to describe what should be done at each step, but it should be noted that recording participant positions and summarizing are key aspects of moving the technical discussion forward. The conversation should move forward, avoiding discussion of previous points, and should be focused on the next technical problem to discuss.
The following is a nonexhaustive list of items which have community consensus.
2. Trivial Bug-Fix Changes
Anyone can commit a trivial patch to fix a spelling or grammatical error in a comment or manual. No developer review required. Post the patch and ChangeLog to libc-alpha/libc-ports with a short message and then push the commit.
Anyone can commit a locale related change where a bugzilla issue exists, government sources are cited, common uses are cited, and if there is an original author for the locale, that original author ACKs the change. No developer review required. Post the patch and ChangeLog to libc-alpha with a short message and then push the commit.
Anyone can commit an update to the libc.pot translation file given that the new libc.pot file came from the upstream translation project. No developer review required. Post the patch and ChangeLog to libc-alpha with a short message and then push the commit.
Anyone can commit a change regenerating a file someone previously failed to regenerate, with the same version of the relevant tool such as autoconf. Only a mention of the commit is needed on libc-alpha, not the diffs of the regeneration.
Anyone can commit a change fixing obvious coding standards problems in a recently committed patch. Post the patch and ChangeLog to libc-alpha with a short message and then push the commit.
Anyone can commit a change adding a bug number to ChangeLog, NEWS or both; there is no need to post such a patch.
Anyone can commit a change adding missing #include directives where it is clear what the right header is for functionality used in a source file. Post the patch and ChangeLog to libc-alpha with a short message and then push the commit.
Anyone can commit a change adding LOCPATH settings for a testcase using locales. Post the patch and ChangeLog to libc-alpha with a short message and then push the commit.
Anyone can commit a change fixing code typos in a commit (e.g. from last-minute untested changes) that break the build or testing, where it is clear what the right fix is. Post the patch and ChangeLog to libc-alpha with a short message and then push the commit.
- Anyone can commit a change fixing the ordering of the Versions files. These files should be sorted for each version (alphabetically, first internal symbols used by other libraries, then public symbols).
Anyone can commit a change to any header to rename __block to __glibc_block or __unused to __glibc_reserved. Multiple versions of the same symbol can be created by appending a number e.g. __glibc_reserved1. Consenus was reached that glibc would use the internal prefix __glibc to avoid name collisions with other tools that comprise the implementation from a standard perspective. See https://sourceware.org/ml/libc-alpha/2012-02/msg00047.html. Note that __unused is used by source from BSD that defines it as the unused attribute for the compiler, while __block is used by Clang's -fblocks extension.
3. Machine Changes
- If you are a maintainer for a machine you are the expert and in a position of leadership. You should post your patches to libc-alpha/libc-ports for general review, but you may immediately commit your patches without the need for review. The community trusts your leadership and experience. If you are unsure about a change seek help and ask specific machine maintainers to review your patches for logical errors.
4. WIP: Kernel syscalls wrappers
This consensus entry is a work in progress:
- If a syscall is obsoleted by another syscall (or otherwise considered obsolete), there is no need to add a wrapper to glibc.
- If a syscall cannot meaningfully be used behind glibc's back, or is not useful in the glibc context except for in the ways in which it is used by glibc, but can only be used directly by glibc, there is no need to add a wrapper to glibc (this probably applies to set_thread_area, for example).
- If there's a glibc function that's not quite a direct wrapper of the syscall but provides all the functionality of it that can usefully be used in a program using glibc, there is no need to add a wrapper to glibc.
- Wrappers to syscalls should be added by default (both for syscalls not used in glibc, and for cases such as futex where the syscall is used in glibc but can usefully be used directly as well) unless there is a clear reason not to. This includes for architecture-specific syscalls.
- If a wrapper is provided, there should also be a header with corresponding declarations (that either provides any relevant constants / structures or includes appropriate kernel neaders providing them).
- There may be cases where a function is meaningful not just with Linux kernels supporting the syscall, and should be provided with some kind of fallback for older kernels, and possibly made part of the glibc API for systems with other kernels as well.
5. Backports to release branches
This follow a different procedure, as described in Release policy documentation.
There is consensus that locales do not need a geographic region associated with them. Language like Esperanto may simply be added to glibc as the eo locale.
7. Other Changes
- There are no well identified subsystem maintainers for subsystems other than architecture-specific code. Seek the consensus of a minimum of one other senior developer before checking in your changes. If you get a scary feeling around the time you are about to push the commit, stop, and go ask for more review. The reviewer may also ask for other opinions if not fully confident in the patch or in their expertise in the relevant area. Cases likely to need more review and a longer period before pushing a commit include:
- Changes adding new public functions.
- Changes involving general design issues.
- Changes that have previously been controversial (including where it has been disputed whether a particular issue is actually a bug).
- Changes that seem particularly risky for all or most users of glibc.
8. Bad Changes
The source tree should always build and the testsuite should not regress without a clear reason posted to libc-alpha. If the build always works, and the testsuite is in a known good state, then the source is ready for any developers to commit changes. There is never any confusion about who or what patch regressed the testsuite, and bugs can be bisected because the source is always in a buildable state (or as close as possible).
- Commits that break the build are immediately reverted.
- Commits that regress the testsuite are immediately reverted.
Note that the libm tests (test-float, test-double, test-ldoubl, test-ifloat, test-idouble, test-ildoubl) test also the accuracy of routines and any new test might fail until the ulp files libm-test-ulps for that architecture is updated (see math/README.libm-tests). Note that unduly large ulps should not get added, these point to problems. So, for these routines, it's expected that the architecture files gets updated (after reviewing the change) as obvious.
9. Best Practice for Larger Changes
For doing larger changes, especially if those involve several architectures that the main author cannot test, the following work flow should be done:
- Create a branch and push it to the public glibc git repository as a personal branch.
- Test it on at least one architecture.
- Ask on the libc-alpha mailing list for review and testing by other parties. Give architecture maintainers enough time for this (an explicit deadline with 5 days should be ok)
- Merge the branch after getting reviews, additional tests - and no test failures.
10. Standards we use
C11 (internally, not exposed via headers):
- Concurrent code in glibc is free from data races (as defined by C11 and its memory model) by default. A data race is if a possible execution contains two memory accesses, at least one of them is a write, at least one is not an atomic operation, and both are not ordered by happens-before. The transition to data-race freedom will be incremental for existing code, but new code should be data-race-free. If we decide to allow a data race in a certain situation because we reason that it is benign, this must get documented and needs closer inspection, repeatedly (e.g., to check that the generated code is okay). To avoid data races, use locks or atomic operations.