summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/.gitignore1
-rw-r--r--Documentation/DocBook/Makefile7
-rw-r--r--Documentation/Makefile.sphinx63
-rw-r--r--Documentation/conf.py414
-rw-r--r--Documentation/dmaengine/provider.txt2
-rw-r--r--Documentation/index.rst23
-rw-r--r--Documentation/kernel-parameters.txt5
-rw-r--r--Documentation/mic/mpssd/mpssd.c4
-rw-r--r--Documentation/security/self-protection.txt28
-rw-r--r--Documentation/sphinx/convert_template.sed18
-rw-r--r--Documentation/sphinx/kernel-doc.py127
-rw-r--r--Documentation/sphinx/post_convert.sed23
-rwxr-xr-xDocumentation/sphinx/tmplcvt19
-rw-r--r--Documentation/sync_file.txt6
-rw-r--r--Documentation/zh_CN/CodingStyle581
-rw-r--r--Makefile5
-rw-r--r--arch/arc/boot/dts/nsimosci.dts14
-rw-r--r--arch/arc/boot/dts/nsimosci_hs.dts14
-rw-r--r--arch/arc/boot/dts/nsimosci_hs_idu.dts14
-rw-r--r--arch/arc/boot/dts/vdk_axs10x_mb.dtsi13
-rw-r--r--arch/arc/boot/dts/vdk_hs38_smp.dts2
-rw-r--r--arch/arc/configs/nsimosci_defconfig3
-rw-r--r--arch/arc/configs/nsimosci_hs_defconfig3
-rw-r--r--arch/arc/configs/nsimosci_hs_smp_defconfig3
-rw-r--r--arch/arc/configs/vdk_hs38_smp_defconfig7
-rw-r--r--drivers/gpu/drm/arc/Makefile2
-rw-r--r--drivers/gpu/drm/arc/arcpgu.h1
-rw-r--r--drivers/gpu/drm/arc/arcpgu_drv.c15
-rw-r--r--drivers/gpu/drm/arc/arcpgu_sim.c128
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c12
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c7
-rwxr-xr-xscripts/kernel-doc393
32 files changed, 1522 insertions, 435 deletions
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
new file mode 100644
index 000000000000..53752db253e3
--- /dev/null
+++ b/Documentation/.gitignore
@@ -0,0 +1 @@
+output
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index d70f9b68174e..e0c7e1e0590b 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -33,10 +33,6 @@ PDF_METHOD = $(prefer-db2x)
PS_METHOD = $(prefer-db2x)
-###
-# The targets that may be used.
-PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs
-
targets += $(DOCBOOKS)
BOOKS := $(addprefix $(obj)/,$(DOCBOOKS))
xmldocs: $(BOOKS)
@@ -63,6 +59,9 @@ installmandocs: mandocs
sort -k 2 -k 1 | uniq -f 1 | sed -e 's: :/:' | \
xargs install -m 644 -t /usr/local/man/man9/
+# no-op for the DocBook toolchain
+epubdocs:
+
###
#External programs used
KERNELDOCXMLREF = $(srctree)/scripts/kernel-doc-xml-ref
diff --git a/Documentation/Makefile.sphinx b/Documentation/Makefile.sphinx
new file mode 100644
index 000000000000..addf32309bc3
--- /dev/null
+++ b/Documentation/Makefile.sphinx
@@ -0,0 +1,63 @@
+# -*- makefile -*-
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXBUILD = sphinx-build
+SPHINXOPTS =
+PAPER =
+BUILDDIR = $(obj)/output
+
+# User-friendly check for sphinx-build
+HAVE_SPHINX := $(shell if which $(SPHINXBUILD) >/dev/null 2>&1; then echo 1; else echo 0; fi)
+
+ifeq ($(HAVE_SPHINX),0)
+
+.DEFAULT:
+ $(warning The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed and in PATH, or set the SPHINXBUILD make variable to point to the full path of the '$(SPHINXBUILD)' executable.)
+ @echo " SKIP Sphinx $@ target."
+
+else # HAVE_SPHINX
+
+# User-friendly check for rst2pdf
+HAVE_RST2PDF := $(shell if python -c "import rst2pdf" >/dev/null 2>&1; then echo 1; else echo 0; fi)
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+KERNELDOC = $(srctree)/scripts/kernel-doc
+KERNELDOC_CONF = -D kerneldoc_srctree=$(srctree) -D kerneldoc_bin=$(KERNELDOC)
+ALLSPHINXOPTS = -D version=$(KERNELVERSION) -D release=$(KERNELRELEASE) -d $(BUILDDIR)/.doctrees $(KERNELDOC_CONF) $(PAPEROPT_$(PAPER)) -c $(srctree)/$(src) $(SPHINXOPTS) $(srctree)/$(src)
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+quiet_cmd_sphinx = SPHINX $@
+ cmd_sphinx = $(SPHINXBUILD) -b $2 $(ALLSPHINXOPTS) $(BUILDDIR)/$2
+
+htmldocs:
+ $(call cmd,sphinx,html)
+
+pdfdocs:
+ifeq ($(HAVE_RST2PDF),0)
+ $(warning The Python 'rst2pdf' module was not found. Make sure you have the module installed to produce PDF output.)
+ @echo " SKIP Sphinx $@ target."
+else # HAVE_RST2PDF
+ $(call cmd,sphinx,pdf)
+endif # HAVE_RST2PDF
+
+epubdocs:
+ $(call cmd,sphinx,epub)
+
+xmldocs:
+ $(call cmd,sphinx,xml)
+
+# no-ops for the Sphinx toolchain
+sgmldocs:
+psdocs:
+mandocs:
+installmandocs:
+
+cleandocs:
+ $(Q)rm -rf $(BUILDDIR)
+
+endif # HAVE_SPHINX
diff --git a/Documentation/conf.py b/Documentation/conf.py
new file mode 100644
index 000000000000..6cc41a0555a3
--- /dev/null
+++ b/Documentation/conf.py
@@ -0,0 +1,414 @@
+# -*- coding: utf-8 -*-
+#
+# The Linux Kernel documentation build configuration file, created by
+# sphinx-quickstart on Fri Feb 12 13:51:46 2016.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('sphinx'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['kernel-doc']
+
+# Gracefully handle missing rst2pdf.
+try:
+ import rst2pdf
+ extensions += ['rst2pdf.pdfbuilder']
+except ImportError:
+ pass
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'The Linux Kernel'
+copyright = '2016, The kernel development community'
+author = 'The kernel development community'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# In a normal build, version and release are are set to KERNELVERSION and
+# KERNELRELEASE, respectively, from the Makefile via Sphinx command line
+# arguments.
+#
+# The following code tries to extract the information by reading the Makefile,
+# when Sphinx is run directly (e.g. by Read the Docs).
+try:
+ makefile_version = None
+ makefile_patchlevel = None
+ for line in open('../Makefile'):
+ key, val = [x.strip() for x in line.split('=', 2)]
+ if key == 'VERSION':
+ makefile_version = val
+ elif key == 'PATCHLEVEL':
+ makefile_patchlevel = val
+ if makefile_version and makefile_patchlevel:
+ break
+except:
+ pass
+finally:
+ if makefile_version and makefile_patchlevel:
+ version = release = makefile_version + '.' + makefile_patchlevel
+ else:
+ sys.stderr.write('Warning: Could not extract kernel version\n')
+ version = release = "unknown version"
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['output']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+primary_domain = 'C'
+highlight_language = 'C'
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+
+# The Read the Docs theme is available from
+# - https://github.com/snide/sphinx_rtd_theme
+# - https://pypi.python.org/pypi/sphinx_rtd_theme
+# - python-sphinx-rtd-theme package (on Debian)
+try:
+ import sphinx_rtd_theme
+ html_theme = 'sphinx_rtd_theme'
+ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
+except ImportError:
+ sys.stderr.write('Warning: The Sphinx \'sphinx_rtd_theme\' HTML theme was not found. Make sure you have the theme installed to produce pretty HTML output. Falling back to the default theme.\n')
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+#html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
+# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr'
+#html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# Now only 'ja' uses this config value
+#html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+#html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'TheLinuxKerneldoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+
+# Latex figure (float) alignment
+#'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'TheLinuxKernel.tex', 'The Linux Kernel Documentation',
+ 'The kernel development community', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'thelinuxkernel', 'The Linux Kernel Documentation',
+ [author], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'TheLinuxKernel', 'The Linux Kernel Documentation',
+ author, 'TheLinuxKernel', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
+
+
+# -- Options for Epub output ----------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = project
+epub_author = author
+epub_publisher = author
+epub_copyright = copyright
+
+# The basename for the epub file. It defaults to the project name.
+#epub_basename = project
+
+# The HTML theme for the epub output. Since the default themes are not
+# optimized for small screen space, using the same theme for HTML and epub
+# output is usually not wise. This defaults to 'epub', a theme designed to save
+# visual space.
+#epub_theme = 'epub'
+
+# The language of the text. It defaults to the language option
+# or 'en' if the language is not set.
+#epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+#epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#epub_identifier = ''
+
+# A unique identification for the text.
+#epub_uid = ''
+
+# A tuple containing the cover image and cover page html template filenames.
+#epub_cover = ()
+
+# A sequence of (type, uri, title) tuples for the guide element of content.opf.
+#epub_guide = ()
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_pre_files = []
+
+# HTML files that should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+epub_exclude_files = ['search.html']
+
+# The depth of the table of contents in toc.ncx.
+#epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#epub_tocdup = True
+
+# Choose between 'default' and 'includehidden'.
+#epub_tocscope = 'default'
+
+# Fix unsupported image types using the Pillow.
+#epub_fix_images = False
+
+# Scale large images.
+#epub_max_image_width = 0
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#epub_show_urls = 'inline'
+
+# If false, no index is generated.
+#epub_use_index = True
+
+#=======
+# rst2pdf
+#
+# Grouping the document tree into PDF files. List of tuples
+# (source start file, target name, title, author, options).
+#
+# See the Sphinx chapter of http://ralsina.me/static/manual.pdf
+#
+# FIXME: Do not add the index file here; the result will be too big. Adding
+# multiple PDF files here actually tries to get the cross-referencing right
+# *between* PDF files.
+pdf_documents = [
+ ('index', u'Kernel', u'Kernel', u'J. Random Bozo'),
+]
+
+# kernel-doc extension configuration for running Sphinx directly (e.g. by Read
+# the Docs). In a normal build, these are supplied from the Makefile via command
+# line arguments.
+kerneldoc_bin = '../scripts/kernel-doc'
+kerneldoc_srctree = '..'
diff --git a/Documentation/dmaengine/provider.txt b/Documentation/dmaengine/provider.txt
index 122b7f4876bb..91ce82d5f0c4 100644
--- a/Documentation/dmaengine/provider.txt
+++ b/Documentation/dmaengine/provider.txt
@@ -323,7 +323,7 @@ supported.
* device_resume
- Resumes a transfer on the channel
- This command should operate synchronously on the channel,
- pausing right away the work of the given channel
+ resuming right away the work of the given channel
* device_terminate_all
- Aborts all the pending and ongoing transfers on the channel
diff --git a/Documentation/index.rst b/Documentation/index.rst
new file mode 100644
index 000000000000..71a276f34c7f
--- /dev/null
+++ b/Documentation/index.rst
@@ -0,0 +1,23 @@
+.. The Linux Kernel documentation master file, created by
+ sphinx-quickstart on Fri Feb 12 13:51:46 2016.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to The Linux Kernel's documentation!
+============================================
+
+Nothing for you to see here *yet*. Please move along.
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 82b42c958d1c..a2a662d4da83 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -3992,8 +3992,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
trace_event=[event-list]
[FTRACE] Set and start specified trace events in order
- to facilitate early boot debugging.
- See also Documentation/trace/events.txt
+ to facilitate early boot debugging. The event-list is a
+ comma separated list of trace events to enable. See
+ also Documentation/trace/events.txt
trace_options=[option-list]
[FTRACE] Enable or disable tracer options at boot.
diff --git a/Documentation/mic/mpssd/mpssd.c b/Documentation/mic/mpssd/mpssd.c
index 30fb842a976d..49db1def1721 100644
--- a/Documentation/mic/mpssd/mpssd.c
+++ b/Documentation/mic/mpssd/mpssd.c
@@ -1538,9 +1538,9 @@ set_cmdline(struct mic_info *mic)
len = snprintf(buffer, PATH_MAX,
"clocksource=tsc highres=off nohz=off ");
- len += snprintf(buffer + len, PATH_MAX,
+ len += snprintf(buffer + len, PATH_MAX - len,
"cpufreq_on;corec6_off;pc3_off;pc6_off ");
- len += snprintf(buffer + len, PATH_MAX,
+ len += snprintf(buffer + len, PATH_MAX - len,
"ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0",
mic->id + 1);
diff --git a/Documentation/security/self-protection.txt b/Documentation/security/self-protection.txt
index babd6378ec05..3010576c9fca 100644
--- a/Documentation/security/self-protection.txt
+++ b/Documentation/security/self-protection.txt
@@ -183,8 +183,9 @@ provide meaningful defenses.
### Canaries, blinding, and other secrets
It should be noted that things like the stack canary discussed earlier
-are technically statistical defenses, since they rely on a (leakable)
-secret value.
+are technically statistical defenses, since they rely on a secret value,
+and such values may become discoverable through an information exposure
+flaw.
Blinding literal values for things like JITs, where the executable
contents may be partially under the control of userspace, need a similar
@@ -199,8 +200,8 @@ working?) in order to maximize their success.
Since the location of kernel memory is almost always instrumental in
mounting a successful attack, making the location non-deterministic
raises the difficulty of an exploit. (Note that this in turn makes
-the value of leaks higher, since they may be used to discover desired
-memory locations.)
+the value of information exposures higher, since they may be used to
+discover desired memory locations.)
#### Text and module base
@@ -222,14 +223,21 @@ become more difficult to locate.
Much of the kernel's dynamic memory (e.g. kmalloc, vmalloc, etc) ends up
being relatively deterministic in layout due to the order of early-boot
initializations. If the base address of these areas is not the same
-between boots, targeting them is frustrated, requiring a leak specific
-to the region.
+between boots, targeting them is frustrated, requiring an information
+exposure specific to the region.
+
+#### Structure layout
+
+By performing a per-build randomization of the layout of sensitive
+structures, attacks must either be tuned to known kernel builds or expose
+enough kernel memory to determine structure layouts before manipulating
+them.
-## Preventing Leaks
+## Preventing Information Exposures
Since the locations of sensitive structures are the primary target for
-attacks, it is important to defend against leaks of both kernel memory
+attacks, it is important to defend against exposure of both kernel memory
addresses and kernel memory contents (since they may contain kernel
addresses or other sensitive things like canary values).
@@ -250,8 +258,8 @@ sure structure holes are cleared.
When releasing memory, it is best to poison the contents (clear stack on
syscall return, wipe heap memory on a free), to avoid reuse attacks that
rely on the old contents of memory. This frustrates many uninitialized
-variable attacks, stack info leaks, heap info leaks, and use-after-free
-attacks.
+variable attacks, stack content exposures, heap content exposures, and
+use-after-free attacks.
### Destination tracking
diff --git a/Documentation/sphinx/convert_template.sed b/Documentation/sphinx/convert_template.sed
new file mode 100644
index 000000000000..c1503fcca4ec
--- /dev/null
+++ b/Documentation/sphinx/convert_template.sed
@@ -0,0 +1,18 @@
+#
+# Pandoc doesn't grok <function> or <structname>, so convert them
+# ahead of time.
+#
+# Use the following escapes to pass through pandoc:
+# $bq = "`"
+# $lt = "<"
+# $gt = ">"
+#
+s%<function>\([^<(]\+\)()</function>%:c:func:$bq\1()$bq%g
+s%<function>\([^<(]\+\)</function>%:c:func:$bq\1()$bq%g
+s%<structname>struct *\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g
+s%struct <structname>\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g
+s%<structname>\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g
+#
+# Wrap docproc directives in para and code blocks.
+#
+s%^\(!.*\)$%<para><code>DOCPROC: \1</code></para>%
diff --git a/Documentation/sphinx/kernel-doc.py b/Documentation/sphinx/kernel-doc.py
new file mode 100644
index 000000000000..4adfb0e91ecc
--- /dev/null
+++ b/Documentation/sphinx/kernel-doc.py
@@ -0,0 +1,127 @@
+# coding=utf-8
+#
+# Copyright © 2016 Intel Corporation
+#
+# 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 (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# Authors:
+# Jani Nikula <jani.nikula@intel.com>
+#
+# Please make sure this works on both python2 and python3.
+#
+
+import os
+import subprocess
+import sys
+import re
+
+from docutils import nodes, statemachine
+from docutils.statemachine import ViewList
+from docutils.parsers.rst import directives
+from sphinx.util.compat import Directive
+
+class KernelDocDirective(Directive):
+ """Extract kernel-doc comments from the specified file"""
+ required_argument = 1
+ optional_arguments = 4
+ option_spec = {
+ 'doc': directives.unchanged_required,
+ 'functions': directives.unchanged_required,
+ 'export': directives.flag,
+ 'internal': directives.flag,
+ }
+ has_content = False
+
+ def run(self):
+ env = self.state.document.settings.env
+ cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno']
+
+ filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
+
+ # Tell sphinx of the dependency
+ env.note_dependency(os.path.abspath(filename))
+
+ tab_width = self.options.get('tab-width', self.state.document.settings.tab_width)
+ source = filename
+
+ # FIXME: make this nicer and more robust against errors
+ if 'export' in self.options:
+ cmd += ['-export']
+ elif 'internal' in self.options:
+ cmd += ['-internal']
+ elif 'doc' in self.options:
+ cmd += ['-function', str(self.options.get('doc'))]
+ elif 'functions' in self.options:
+ for f in str(self.options.get('functions')).split(' '):
+ cmd += ['-function', f]
+
+ cmd += [filename]
+
+ try:
+ env.app.verbose('calling kernel-doc \'%s\'' % (" ".join(cmd)))
+
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
+ out, err = p.communicate()
+
+ # python2 needs conversion to unicode.
+ # python3 with universal_newlines=True returns strings.
+ if sys.version_info.major < 3:
+ out, err = unicode(out, 'utf-8'), unicode(err, 'utf-8')
+
+ if p.returncode != 0:
+ sys.stderr.write(err)
+
+ env.app.warn('kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode))
+ return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
+ elif env.config.kerneldoc_verbosity > 0:
+ sys.stderr.write(err)
+
+ lines = statemachine.string2lines(out, tab_width, convert_whitespace=True)
+ result = ViewList()
+
+ lineoffset = 0;
+ line_regex = re.compile("^#define LINENO ([0-9]+)$")
+ for line in lines:
+ match = line_regex.search(line)
+ if match:
+ # sphinx counts lines from 0
+ lineoffset = int(match.group(1)) - 1
+ # we must eat our comments since the upset the markup
+ else:
+ result.append(line, source, lineoffset)
+ lineoffset += 1
+
+ node = nodes.section()
+ node.document = self.state.document
+ self.state.nested_parse(result, self.content_offset, node)
+
+ return node.children
+
+ except Exception as e:
+ env.app.warn('kernel-doc \'%s\' processing failed with: %s' %
+ (" ".join(cmd), str(e)))
+ return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
+
+def setup(app):
+ app.add_config_value('kerneldoc_bin', None, 'env')
+ app.add_config_value('kerneldoc_srctree', None, 'env')
+ app.add_config_value('kerneldoc_verbosity', 1, 'env')
+
+ app.add_directive('kernel-doc', KernelDocDirective)
diff --git a/Documentation/sphinx/post_convert.sed b/Documentation/sphinx/post_convert.sed
new file mode 100644
index 000000000000..392770bac53b
--- /dev/null
+++ b/Documentation/sphinx/post_convert.sed
@@ -0,0 +1,23 @@
+#
+# Unescape.
+#
+s/$bq/`/g
+s/$lt/</g
+s/$gt/>/g
+#
+# pandoc thinks that both "_" needs to be escaped. Remove the extra
+# backslashes.
+#
+s/\\_/_/g
+#
+# Unwrap docproc directives.
+#
+s/^``DOCPROC: !E\(.*\)``$/.. kernel-doc:: \1\n :export:/
+s/^``DOCPROC: !I\(.*\)``$/.. kernel-doc:: \1\n :internal:/
+s/^``DOCPROC: !F\([^ ]*\) \(.*\)``$/.. kernel-doc:: \1\n :functions: \2/
+s/^``DOCPROC: !P\([^ ]*\) \(.*\)``$/.. kernel-doc:: \1\n :doc: \2/
+s/^``DOCPROC: \(!.*\)``$/.. WARNING: DOCPROC directive not supported: \1/
+#
+# Trim trailing whitespace.
+#
+s/[[:space:]]*$//
diff --git a/Documentation/sphinx/tmplcvt b/Documentation/sphinx/tmplcvt
new file mode 100755
index 000000000000..909a73065e0a
--- /dev/null
+++ b/Documentation/sphinx/tmplcvt
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# Convert a template file into something like RST
+#
+# fix <function>
+# feed to pandoc
+# fix \_
+# title line?
+#
+
+in=$1
+rst=$2
+tmp=$rst.tmp
+
+cp $in $tmp
+sed --in-place -f convert_template.sed $tmp
+pandoc -s -S -f docbook -t rst -o $rst $tmp
+sed --in-place -f post_convert.sed $rst
+rm $tmp
diff --git a/Documentation/sync_file.txt b/Documentation/sync_file.txt
index eaf8297dbca2..e8e2ebafe5fa 100644
--- a/Documentation/sync_file.txt
+++ b/Documentation/sync_file.txt
@@ -6,8 +6,8 @@
This document serves as a guide for device drivers writers on what the
sync_file API is, and how drivers can support it. Sync file is the carrier of
-the fences(struct fence) that needs to synchronized between drivers or across
-process boundaries.
+the fences(struct fence) that are needed to synchronize between drivers or
+across process boundaries.
The sync_file API is meant to be used to send and receive fence information
to/from userspace. It enables userspace to do explicit fencing, where instead
@@ -32,7 +32,7 @@ in-fences and out-fences
Sync files can go either to or from userspace. When a sync_file is sent from
the driver to userspace we call the fences it contains 'out-fences'. They are
related to a buffer that the driver is processing or is going to process, so
-the driver an create out-fence to be able to notify, through fence_signal(),
+the driver creates an out-fence to be able to notify, through fence_signal(),
when it has finished using (or processing) that buffer. Out-fences are fences
that the driver creates.
diff --git a/Documentation/zh_CN/CodingStyle b/Documentation/zh_CN/CodingStyle
index 654afd72eb24..bbb9d6ae05ca 100644
--- a/Documentation/zh_CN/CodingStyle
+++ b/Documentation/zh_CN/CodingStyle
@@ -24,34 +24,33 @@ Documentation/CodingStyle的中文翻译
Linux内核代ç é£Žæ ¼
-这是一个简短的文档,æè¿°äº†linux内核的首选代ç é£Žæ ¼ã€‚代ç é£Žæ ¼æ˜¯å› äººè€Œå¼‚的,而且我
-䏿„¿æ„把我的观点强加给任何人,ä¸è¿‡è¿™é‡Œæ‰€è®²è¿°çš„æ˜¯æˆ‘å¿…é¡»è¦ç»´æŠ¤çš„ä»£ç æ‰€éµå®ˆçš„风格,
-并且我也希望ç»å¤§å¤šæ•°å…¶ä»–代ç ä¹Ÿèƒ½éµå®ˆè¿™ä¸ªé£Žæ ¼ã€‚è¯·åœ¨å†™ä»£ç æ—¶è‡³å°‘考虑一下本文所述的
-风格。
+这是一个简短的文档,æè¿°äº† linux 内核的首选代ç é£Žæ ¼ã€‚代ç é£Žæ ¼æ˜¯å› äººè€Œå¼‚的,而且我
+䏿„¿æ„æŠŠè‡ªå·±çš„è§‚ç‚¹å¼ºåŠ ç»™ä»»ä½•äººï¼Œä½†è¿™å°±åƒæˆ‘去åšä»»ä½•事情都必须éµå¾ªçš„原则那样,我也
+希望在ç»å¤§å¤šæ•°äº‹ä¸Šä¿æŒè¿™ç§çš„æ€åº¦ã€‚è¯·ï¼ˆåœ¨å†™ä»£ç æ—¶ï¼‰è‡³å°‘考虑一下这里的代ç é£Žæ ¼ã€‚
-首先,我建议你打å°ä¸€ä»½GNU代ç è§„范,然åŽä¸è¦è¯»å®ƒã€‚烧了它,这是一个具有é‡å¤§è±¡å¾æ€§
-æ„义的动作。
+首先,我建议你打å°ä¸€ä»½ GNU 代ç è§„范,然åŽä¸è¦è¯»ã€‚烧了它,这是一个具有é‡å¤§è±¡å¾æ€§æ„义
+的动作。
ä¸ç®¡æ€Žæ ·ï¼ŒçŽ°åœ¨æˆ‘ä»¬å¼€å§‹ï¼š
- 第一章:缩进
+ 第一章:缩进
-制表符是8个字符,所以缩进也是8个字符。有些异端è¿åŠ¨è¯•å›¾å°†ç¼©è¿›å˜ä¸º4(乃至2)个字符
-深,这几乎相当于å°è¯•将圆周率的值定义为3。
+制表符是 8 个字符,所以缩进也是 8 个字符。有些异端è¿åŠ¨è¯•å›¾å°†ç¼©è¿›å˜ä¸º 4(甚至 2ï¼ï¼‰
+个字符深,这几乎相当于å°è¯•将圆周率的值定义为 3。
ç†ç”±ï¼šç¼©è¿›çš„全部æ„义就在于清楚的定义一个控制å—起止于何处。尤其是当你盯ç€ä½ çš„å±å¹•
-连续看了20å°æ—¶ä¹‹åŽï¼Œä½ å°†ä¼šå‘现大一点的缩进会使你更容易分辨缩进。
+连续看了 20 å°æ—¶ä¹‹åŽï¼Œä½ å°†ä¼šå‘现大一点的缩进会使你更容易分辨缩进。
-现在,有些人会抱怨8个字符的缩进会使代ç å‘å³è¾¹ç§»åŠ¨çš„å¤ªè¿œï¼Œåœ¨80个字符的终端å±å¹•上
-就很难读这样的代ç ã€‚这个问题的答案是,如果你需è¦3级以上的缩进,ä¸ç®¡ç”¨ä½•ç§æ–¹å¼ä½ 
+现在,有些人会抱怨 8 个字符的缩进会使代ç å‘å³è¾¹ç§»åŠ¨çš„å¤ªè¿œï¼Œåœ¨ 80 个字符的终端å±å¹•上
+就很难读这样的代ç ã€‚è¿™ä¸ªé—®é¢˜çš„ç­”æ¡ˆæ˜¯ï¼Œå¦‚æžœä½ éœ€è¦ 3 级以上的缩进,ä¸ç®¡ç”¨ä½•ç§æ–¹å¼ä½ 
的代ç å·²ç»æœ‰é—®é¢˜äº†ï¼Œåº”该修正你的程åºã€‚
-简而言之,8个字符的缩进å¯ä»¥è®©ä»£ç æ›´å®¹æ˜“阅读,还有一个好处是当你的函数嵌套太深的
+简而言之,8 个字符的缩进å¯ä»¥è®©ä»£ç æ›´å®¹æ˜“阅读,还有一个好处是当你的函数嵌套太深的
时候å¯ä»¥ç»™ä½ è­¦å‘Šã€‚留心这个警告。
-在switch语å¥ä¸­æ¶ˆé™¤å¤šçº§ç¼©è¿›çš„é¦–é€‰çš„æ–¹å¼æ˜¯è®©â€œswitchâ€å’Œä»Žå±žäºŽå®ƒçš„“caseâ€æ ‡ç­¾å¯¹é½äºŽåŒ
-一列,而ä¸è¦â€œä¸¤æ¬¡ç¼©è¿›â€â€œcaseâ€æ ‡ç­¾ã€‚比如:
+在 switch 语å¥ä¸­æ¶ˆé™¤å¤šçº§ç¼©è¿›çš„é¦–é€‰çš„æ–¹å¼æ˜¯è®© “switch†和从属于它的 “case†标签
+对é½äºŽåŒä¸€åˆ—,而ä¸è¦ “两次缩进†“case†标签。比如:
switch (suffix) {
case 'G':
@@ -70,7 +69,6 @@ Documentation/CodingStyle的中文翻译
break;
}
-
ä¸è¦æŠŠå¤šä¸ªè¯­å¥æ”¾åœ¨ä¸€è¡Œé‡Œï¼Œé™¤éžä½ æœ‰ä»€ä¹ˆä¸œè¥¿è¦éšè—:
if (condition) do_this;
@@ -79,7 +77,7 @@ Documentation/CodingStyle的中文翻译
也ä¸è¦åœ¨ä¸€è¡Œé‡Œæ”¾å¤šä¸ªèµ‹å€¼è¯­å¥ã€‚内核代ç é£Žæ ¼è¶…级简å•。就是é¿å…å¯èƒ½å¯¼è‡´åˆ«äººè¯¯è¯»çš„表
è¾¾å¼ã€‚
-é™¤äº†æ³¨é‡Šã€æ–‡æ¡£å’ŒKconfig之外,ä¸è¦ä½¿ç”¨ç©ºæ ¼æ¥ç¼©è¿›ï¼Œå‰é¢çš„例孿˜¯ä¾‹å¤–,是有æ„为之。
+é™¤äº†æ³¨é‡Šã€æ–‡æ¡£å’Œ Kconfig 之外,ä¸è¦ä½¿ç”¨ç©ºæ ¼æ¥ç¼©è¿›ï¼Œå‰é¢çš„例孿˜¯ä¾‹å¤–,是有æ„为之。
选用一个好的编辑器,ä¸è¦åœ¨è¡Œå°¾ç•™ç©ºæ ¼ã€‚
@@ -88,27 +86,18 @@ Documentation/CodingStyle的中文翻译
代ç é£Žæ ¼çš„æ„ä¹‰å°±åœ¨äºŽä½¿ç”¨å¹³å¸¸ä½¿ç”¨çš„å·¥å…·æ¥ç»´æŒä»£ç çš„å¯è¯»æ€§å’Œå¯ç»´æŠ¤æ€§ã€‚
-æ¯ä¸€è¡Œçš„长度的é™åˆ¶æ˜¯80列,我们强烈建议您éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ã€‚
+æ¯ä¸€è¡Œçš„长度的é™åˆ¶æ˜¯ 80 列,我们强烈建议您éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ã€‚
-长于80列的语å¥è¦æ‰“æ•£æˆæœ‰æ„义的片段。æ¯ä¸ªç‰‡æ®µè¦æ˜Žæ˜¾çŸ­äºŽåŽŸæ¥çš„语å¥ï¼Œè€Œä¸”放置的ä½ç½®
-也明显的é å³ã€‚åŒæ ·çš„è§„åˆ™ä¹Ÿé€‚ç”¨äºŽæœ‰å¾ˆé•¿å‚æ•°åˆ—è¡¨çš„å‡½æ•°å¤´ã€‚é•¿å­—ç¬¦ä¸²ä¹Ÿè¦æ‰“æ•£æˆè¾ƒçŸ­çš„
-字符串。唯一的例外是超过80列å¯ä»¥å¤§å¹…度æé«˜å¯è¯»æ€§å¹¶ä¸”ä¸ä¼šéšè—ä¿¡æ¯çš„æƒ…况。
-
-void fun(int a, int b, int c)
-{
- if (condition)
- printk(KERN_WARNING "Warning this is a long printk with "
- "3 parameters a: %u b: %u "
- "c: %u \n", a, b, c);
- else
- next_statement;
-}
+长于 80 列的语å¥è¦æ‰“æ•£æˆæœ‰æ„义的片段。除éžè¶…过 80 列能显著增加å¯è¯»æ€§ï¼Œå¹¶ä¸”ä¸ä¼šéšè—
+ä¿¡æ¯ã€‚å­ç‰‡æ®µè¦æ˜Žæ˜¾çŸ­äºŽæ¯ç‰‡æ®µï¼Œå¹¶æ˜Žæ˜¾é å³ã€‚è¿™åŒæ ·é€‚用于有ç€å¾ˆé•¿å‚数列表的函数头。
+然而,ç»å¯¹ä¸è¦æ‰“散对用户å¯è§çš„字符串,例如 printk ä¿¡æ¯ï¼Œå› ä¸ºè¿™å°†å¯¼è‡´æ— æ³• grep 这些
+ä¿¡æ¯ã€‚
第三章:大括å·å’Œç©ºæ ¼çš„æ”¾ç½®
C语言风格中å¦å¤–一个常è§é—®é¢˜æ˜¯å¤§æ‹¬å·çš„æ”¾ç½®ã€‚和缩进大å°ä¸åŒï¼Œé€‰æ‹©æˆ–弃用æŸç§æ”¾ç½®ç­–
-略并没有多少技术上的原因,ä¸è¿‡é¦–选的方å¼ï¼Œå°±åƒKernighanå’ŒRitchie展示给我们的,是
-æŠŠèµ·å§‹å¤§æ‹¬å·æ”¾åœ¨è¡Œå°¾ï¼Œè€ŒæŠŠç»“æŸå¤§æ‹¬å·æ”¾åœ¨è¡Œé¦–,所以:
+略并没有多少技术上的原因,ä¸è¿‡é¦–选的方å¼ï¼Œå°±åƒ Kernighan å’Œ Ritchie 展示给我们的,
+æ˜¯æŠŠèµ·å§‹å¤§æ‹¬å·æ”¾åœ¨è¡Œå°¾ï¼Œè€ŒæŠŠç»“æŸå¤§æ‹¬å·æ”¾åœ¨è¡Œé¦–,所以:
if (x is true) {
we do y
@@ -134,12 +123,12 @@ C语言风格中å¦å¤–一个常è§é—®é¢˜æ˜¯å¤§æ‹¬å·çš„æ”¾ç½®ã€‚和缩进大å°ä
body of function
}
-全世界的异端å¯èƒ½ä¼šæŠ±æ€¨è¿™ä¸ªä¸ä¸€è‡´æ€§æ˜¯â€¦â€¦å‘ƒâ€¦â€¦ä¸ä¸€è‡´çš„,ä¸è¿‡æ‰€æœ‰æ€ç»´å¥å…¨çš„人都知é“(
-a)K&R是_正确的_,并且(b)K&R是正确的。此外,ä¸ç®¡æ€Žæ ·å‡½æ•°éƒ½æ˜¯ç‰¹æ®Šçš„(在C语言中
-,函数是ä¸èƒ½åµŒå¥—的)。
+全世界的异端å¯èƒ½ä¼šæŠ±æ€¨è¿™ä¸ªä¸ä¸€è‡´æ€§æ˜¯â€¦â€¦å‘ƒâ€¦â€¦ä¸ä¸€è‡´çš„,ä¸è¿‡æ‰€æœ‰æ€ç»´å¥å…¨çš„人都知é“
+(a) K&R 是 _正确的_,并且 (b) K&R 是正确的。此外,ä¸ç®¡æ€Žæ ·å‡½æ•°éƒ½æ˜¯ç‰¹æ®Šçš„(C
+函数是ä¸èƒ½åµŒå¥—的)。
-注æ„结æŸå¤§æ‹¬å·ç‹¬è‡ªå æ®ä¸€è¡Œï¼Œé™¤éžå®ƒåŽé¢è·Ÿç€åŒä¸€ä¸ªè¯­å¥çš„剩余部分,也就是do语å¥ä¸­çš„
-“whileâ€æˆ–者if语å¥ä¸­çš„“elseâ€ï¼Œåƒè¿™æ ·ï¼š
+注æ„结æŸå¤§æ‹¬å·ç‹¬è‡ªå æ®ä¸€è¡Œï¼Œé™¤éžå®ƒåŽé¢è·Ÿç€åŒä¸€ä¸ªè¯­å¥çš„剩余部分,也就是 do 语å¥ä¸­çš„
+“while†或者 if 语å¥ä¸­çš„ “elseâ€ï¼Œåƒè¿™æ ·ï¼š
do {
body of do-loop
@@ -158,41 +147,50 @@ a)K&R是_正确的_,并且(b)K&R是正确的。此外,ä¸ç®¡æ€Žæ ·å‡½æ
ç†ç”±ï¼šK&R。
也请注æ„è¿™ç§å¤§æ‹¬å·çš„æ”¾ç½®æ–¹å¼ä¹Ÿèƒ½ä½¿ç©ºï¼ˆæˆ–者差ä¸å¤šç©ºçš„ï¼‰è¡Œçš„æ•°é‡æœ€å°åŒ–ï¼ŒåŒæ—¶ä¸å¤±å¯
-读性。因此,由于你的å±å¹•上的新行是ä¸å¯å†ç”Ÿèµ„æºï¼ˆæƒ³æƒ³25行的终端å±å¹•),你将会有更
+读性。因此,由于你的å±å¹•上的新行是ä¸å¯å†ç”Ÿèµ„æºï¼ˆæƒ³æƒ³ 25 行的终端å±å¹•),你将会有更
å¤šçš„ç©ºè¡Œæ¥æ”¾ç½®æ³¨é‡Šã€‚
å½“åªæœ‰ä¸€ä¸ªå•独的语å¥çš„æ—¶å€™ï¼Œä¸ç”¨åŠ ä¸å¿…è¦çš„大括å·ã€‚
-if (condition)
- action();
+ if (condition)
+ action();
+
+和
+
+ if (condition)
+ do_this();
+ else
+ do_that();
-这点ä¸é€‚用于本身为æŸä¸ªæ¡ä»¶è¯­å¥çš„一个分支的å•独语å¥ã€‚这时需è¦åœ¨ä¸¤ä¸ªåˆ†æ”¯é‡Œéƒ½ä½¿ç”¨å¤§
-括å·ã€‚
+这并ä¸é€‚ç”¨äºŽåªæœ‰ä¸€ä¸ªæ¡ä»¶åˆ†æ”¯æ˜¯å•语å¥çš„æƒ…况;这时所有分支都è¦ä½¿ç”¨å¤§æ‹¬å·ï¼š
-if (condition) {
- do_this();
- do_that();
-} else {
- otherwise();
-}
+ if (condition) {
+ do_this();
+ do_that();
+ } else {
+ otherwise();
+ }
3.1:空格
-Linux内核的空格使用方å¼ï¼ˆä¸»è¦ï¼‰å–决于它是用于函数还是关键字。(大多数)关键字åŽ
-è¦åŠ ä¸€ä¸ªç©ºæ ¼ã€‚å€¼å¾—æ³¨æ„的例外是sizeofã€typeofã€alignofå’Œ__attribute__,这些关键字
-æŸäº›ç¨‹åº¦ä¸Šçœ‹èµ·æ¥æ›´åƒå‡½æ•°ï¼ˆå®ƒä»¬åœ¨Linux里也常常伴éšå°æ‹¬å·è€Œä½¿ç”¨ï¼Œå°½ç®¡åœ¨C语言里这样
-çš„å°æ‹¬å·ä¸æ˜¯å¿…需的,就åƒâ€œstruct fileinfo infoâ€å£°æ˜Žè¿‡åŽçš„“sizeof infoâ€ï¼‰ã€‚
+Linux 内核的空格使用方å¼ï¼ˆä¸»è¦ï¼‰å–决于它是用于函数还是关键字。(大多数)关键字åŽ
+è¦åŠ ä¸€ä¸ªç©ºæ ¼ã€‚å€¼å¾—æ³¨æ„的例外是 sizeofã€typeofã€alignof å’Œ __attribute__,这些
+关键字æŸäº›ç¨‹åº¦ä¸Šçœ‹èµ·æ¥æ›´åƒå‡½æ•°ï¼ˆå®ƒä»¬åœ¨ Linux 里也常常伴éšå°æ‹¬å·è€Œä½¿ç”¨ï¼Œå°½ç®¡åœ¨ C 里
+è¿™æ ·çš„å°æ‹¬å·ä¸æ˜¯å¿…éœ€çš„ï¼Œå°±åƒ â€œstruct fileinfo info†声明过åŽçš„ “sizeof infoâ€ï¼‰ã€‚
æ‰€ä»¥åœ¨è¿™äº›å…³é”®å­—ä¹‹åŽæ”¾ä¸€ä¸ªç©ºæ ¼ï¼š
+
if, switch, case, for, do, while
-但是ä¸è¦åœ¨sizeofã€typeofã€alignof或者__attribute__è¿™äº›å…³é”®å­—ä¹‹åŽæ”¾ç©ºæ ¼ã€‚例如,
+
+但是ä¸è¦åœ¨ sizeofã€typeofã€alignof 或者 __attribute__ è¿™äº›å…³é”®å­—ä¹‹åŽæ”¾ç©ºæ ¼ã€‚例如,
+
s = sizeof(struct file);
ä¸è¦åœ¨å°æ‹¬å·é‡Œçš„表达å¼ä¸¤ä¾§åŠ ç©ºæ ¼ã€‚è¿™æ˜¯ä¸€ä¸ªå例:
s = sizeof( struct file );
-当声明指针类型或者返回指针类型的函数时,“*â€çš„é¦–é€‰ä½¿ç”¨æ–¹å¼æ˜¯ä½¿ä¹‹é è¿‘å˜é‡å或者函
+当声明指针类型或者返回指针类型的函数时,“*â€ çš„é¦–é€‰ä½¿ç”¨æ–¹å¼æ˜¯ä½¿ä¹‹é è¿‘å˜é‡å或者函
æ•°åï¼Œè€Œä¸æ˜¯é è¿‘类型å。例å­ï¼š
char *linux_banner;
@@ -204,15 +202,18 @@ Linux内核的空格使用方å¼ï¼ˆä¸»è¦ï¼‰å–决于它是用于函数还是关
= + - < > * / % | & ^ <= >= == != ? :
但是一元æ“作符åŽä¸è¦åŠ ç©ºæ ¼ï¼š
+
& * + - ~ ! sizeof typeof alignof __attribute__ defined
åŽç¼€è‡ªåŠ å’Œè‡ªå‡ä¸€å…ƒæ“作符å‰ä¸åŠ ç©ºæ ¼ï¼š
+
++ --
å‰ç¼€è‡ªåŠ å’Œè‡ªå‡ä¸€å…ƒæ“作符åŽä¸åŠ ç©ºæ ¼ï¼š
+
++ --
-“.â€å’Œâ€œ->â€ç»“构体æˆå‘˜æ“作符å‰åŽä¸åŠ ç©ºæ ¼ã€‚
+‘.’ å’Œ “->†结构体æˆå‘˜æ“作符å‰åŽä¸åŠ ç©ºæ ¼ã€‚
ä¸è¦åœ¨è¡Œå°¾ç•™ç©ºç™½ã€‚有些å¯ä»¥è‡ªåŠ¨ç¼©è¿›çš„ç¼–è¾‘å™¨ä¼šåœ¨æ–°è¡Œçš„è¡Œé¦–åŠ å…¥é€‚é‡çš„空白,然åŽä½ 
å°±å¯ä»¥ç›´æŽ¥åœ¨é‚£ä¸€è¡Œè¾“入代ç ã€‚ä¸è¿‡å‡å¦‚ä½ æœ€åŽæ²¡æœ‰åœ¨é‚£ä¸€è¡Œè¾“入代ç ï¼Œæœ‰äº›ç¼–辑器就ä¸
@@ -225,23 +226,23 @@ Linux内核的空格使用方å¼ï¼ˆä¸»è¦ï¼‰å–决于它是用于函数还是关
第四章:命å
-C是一个简朴的语言,你的命å也应该这样。和Modula-2å’ŒPascal程åºå‘˜ä¸åŒï¼ŒC程åºå‘˜ä¸ä½¿
-用类似ThisVariableIsATemporaryCounter这样åŽä¸½çš„å字。C程åºå‘˜ä¼šç§°é‚£ä¸ªå˜é‡ä¸ºâ€œtmpâ€
-,这样写起æ¥ä¼šæ›´å®¹æ˜“,而且至少ä¸ä¼šä»¤å…¶éš¾äºŽç†è§£ã€‚
+C是一个简朴的语言,你的命å也应该这样。和 Modula-2 å’Œ Pascal 程åºå‘˜ä¸åŒï¼ŒC 程åºå‘˜
+ä¸ä½¿ç”¨ç±»ä¼¼ ThisVariableIsATemporaryCounter 这样åŽä¸½çš„å字。C 程åºå‘˜ä¼šç§°é‚£ä¸ªå˜é‡
+为 “tmpâ€ï¼Œè¿™æ ·å†™èµ·æ¥ä¼šæ›´å®¹æ˜“,而且至少ä¸ä¼šä»¤å…¶éš¾äºŽç†è§£ã€‚
ä¸è¿‡ï¼Œè™½ç„¶æ··ç”¨å¤§å°å†™çš„åå­—æ˜¯ä¸æå€¡ä½¿ç”¨çš„ï¼Œä½†æ˜¯å…¨å±€å˜é‡è¿˜æ˜¯éœ€è¦ä¸€ä¸ªå…·æè¿°æ€§çš„åå­—
-。称一个全局函数为“fooâ€æ˜¯ä¸€ä¸ªéš¾ä»¥é¥¶æ•的错误。
+。称一个全局函数为 “foo†是一个难以饶æ•的错误。
全局å˜é‡ï¼ˆåªæœ‰å½“你真正需è¦å®ƒä»¬çš„æ—¶å€™å†ç”¨å®ƒï¼‰éœ€è¦æœ‰ä¸€ä¸ªå…·æè¿°æ€§çš„å字,就åƒå…¨å±€å‡½
-数。如果你有一个å¯ä»¥è®¡ç®—活动用户数é‡çš„函数,你应该å«å®ƒâ€œcount_active_users()â€æˆ–者
-类似的å字,你ä¸åº”该å«å®ƒâ€œcntuser()â€ã€‚
+数。如果你有一个å¯ä»¥è®¡ç®—活动用户数é‡çš„函数,你应该å«å®ƒ “count_active_users()â€
+或者类似的å字,你ä¸åº”该å«å®ƒ “cntuser()â€ã€‚
在函数å中包å«å‡½æ•°ç±»åž‹ï¼ˆæ‰€è°“çš„åŒˆç‰™åˆ©å‘½åæ³•)是脑å­å‡ºäº†é—®é¢˜â€”—编译器知é“那些类型而
且能够检查那些类型,这样åšåªèƒ½æŠŠç¨‹åºå‘˜å¼„糊涂了。难怪微软总是制造出有问题的程åºã€‚
本地å˜é‡å应该简短,而且能够表达相关的å«ä¹‰ã€‚å¦‚æžœä½ æœ‰ä¸€äº›éšæœºçš„æ•´æ•°åž‹çš„循环计数器
-,它应该被称为“iâ€ã€‚å«å®ƒâ€œloop_counterâ€å¹¶æ— ç›Šå¤„,如果它没有被误解的å¯èƒ½çš„è¯ã€‚类似
-的,“tmpâ€å¯ä»¥ç”¨æ¥ç§°å‘¼ä»»æ„类型的临时å˜é‡ã€‚
+,它应该被称为 “iâ€ã€‚å«å®ƒ “loop_counter†并无益处,如果它没有被误解的å¯èƒ½çš„è¯ã€‚
+类似的,“tmp†å¯ä»¥ç”¨æ¥ç§°å‘¼ä»»æ„类型的临时å˜é‡ã€‚
如果你怕混淆了你的本地å˜é‡å,你就é‡åˆ°å¦ä¸€ä¸ªé—®é¢˜äº†ï¼Œå«åšå‡½æ•°å¢žé•¿è·å°”蒙失衡综åˆç—‡
。请看第六章(函数)。
@@ -249,9 +250,9 @@ C是一个简朴的语言,你的命å也应该这样。和Modula-2å’ŒPascalç¨
第五章:Typedef
-ä¸è¦ä½¿ç”¨ç±»ä¼¼â€œvps_tâ€ä¹‹ç±»çš„东西。
+ä¸è¦ä½¿ç”¨ç±»ä¼¼ “vps_t†之类的东西。
-对结构体和指针使用typedef是一个错误。当你在代ç é‡Œçœ‹åˆ°ï¼š
+对结构体和指针使用 typedef 是一个错误。当你在代ç é‡Œçœ‹åˆ°ï¼š
vps_t a;
@@ -261,91 +262,91 @@ C是一个简朴的语言,你的命å也应该这样。和Modula-2å’ŒPascalç¨
struct virtual_container *a;
-你就知é““aâ€æ˜¯ä»€ä¹ˆäº†ã€‚
+ä½ å°±çŸ¥é“ â€œa†是什么了。
-很多人认为typedef“能æé«˜å¯è¯»æ€§â€ã€‚å®žé™…ä¸æ˜¯è¿™æ ·çš„。它们åªåœ¨ä¸‹åˆ—情况下有用:
+很多人认为 typedef “能æé«˜å¯è¯»æ€§â€ã€‚å®žé™…ä¸æ˜¯è¿™æ ·çš„。它们åªåœ¨ä¸‹åˆ—情况下有用:
- (a) 完全ä¸é€æ˜Žçš„å¯¹è±¡ï¼ˆè¿™ç§æƒ…况下è¦ä¸»åŠ¨ä½¿ç”¨typedefæ¥éšè—这个对象实际上是什么)。
+ (a) 完全ä¸é€æ˜Žçš„å¯¹è±¡ï¼ˆè¿™ç§æƒ…况下è¦ä¸»åŠ¨ä½¿ç”¨ typedef æ¥éšè—这个对象实际上是什么)。
- 例如:“pte_tâ€ç­‰ä¸é€æ˜Žå¯¹è±¡ï¼Œä½ åªèƒ½ç”¨åˆé€‚的访问函数æ¥è®¿é—®å®ƒä»¬ã€‚
+ 例如:“pte_t†等ä¸é€æ˜Žå¯¹è±¡ï¼Œä½ åªèƒ½ç”¨åˆé€‚的访问函数æ¥è®¿é—®å®ƒä»¬ã€‚
- 注æ„ï¼ä¸é€æ˜Žæ€§å’Œâ€œè®¿é—®å‡½æ•°â€æœ¬èº«æ˜¯ä¸å¥½çš„。我们使用pte_t等类型的原因在于真的是
+ 注æ„ï¼ä¸é€æ˜Žæ€§å’Œâ€œè®¿é—®å‡½æ•°â€æœ¬èº«æ˜¯ä¸å¥½çš„。我们使用 pte_t 等类型的原因在于真的是
完全没有任何共用的å¯è®¿é—®ä¿¡æ¯ã€‚
- (b) 清楚的整数类型,如此,这层抽象就å¯ä»¥å¸®åŠ©æ¶ˆé™¤åˆ°åº•æ˜¯â€œintâ€è¿˜æ˜¯â€œlongâ€çš„æ··æ·†ã€‚
+ (b) 清楚的整数类型,如此,这层抽象就å¯ä»¥å¸®åŠ©æ¶ˆé™¤åˆ°åº•æ˜¯ “int†还是 “long†的混淆。
- u8/u16/u32是完全没有问题的typedef,ä¸è¿‡å®ƒä»¬æ›´ç¬¦åˆç±»åˆ«(d)è€Œä¸æ˜¯è¿™é‡Œã€‚
+ u8/u16/u32 是完全没有问题的 typedef,ä¸è¿‡å®ƒä»¬æ›´ç¬¦åˆç±»åˆ« (d) è€Œä¸æ˜¯è¿™é‡Œã€‚
- 冿¬¡æ³¨æ„ï¼è¦è¿™æ ·åšï¼Œå¿…须事出有因。如果æŸä¸ªå˜é‡æ˜¯â€œunsigned long“,那么没有必è¦
+ 冿¬¡æ³¨æ„ï¼è¦è¿™æ ·åšï¼Œå¿…须事出有因。如果æŸä¸ªå˜é‡æ˜¯ “unsigned long“,那么没有必è¦
typedef unsigned long myflags_t;
- ä¸è¿‡å¦‚果有一个明确的原因,比如它在æŸç§æƒ…况下å¯èƒ½ä¼šæ˜¯ä¸€ä¸ªâ€œunsigned intâ€è€Œåœ¨
- 其他情况下å¯èƒ½ä¸ºâ€œunsigned longâ€ï¼Œé‚£ä¹ˆå°±ä¸è¦çŠ¹è±«ï¼Œè¯·åŠ¡å¿…ä½¿ç”¨typedef。
+ ä¸è¿‡å¦‚果有一个明确的原因,比如它在æŸç§æƒ…况下å¯èƒ½ä¼šæ˜¯ä¸€ä¸ª “unsigned int†而在
+ 其他情况下å¯èƒ½ä¸º “unsigned longâ€ï¼Œé‚£ä¹ˆå°±ä¸è¦çŠ¹è±«ï¼Œè¯·åŠ¡å¿…ä½¿ç”¨ typedef。
(c) 当你使用sparse按字é¢çš„创建一个新类型æ¥åšç±»åž‹æ£€æŸ¥çš„æ—¶å€™ã€‚
(d) 和标准C99类型相åŒçš„类型,在æŸäº›ä¾‹å¤–的情况下。
- 虽然让眼ç›å’Œè„‘ç­‹æ¥é€‚应新的标准类型比如“uint32_tâ€ä¸éœ€è¦èŠ±å¾ˆå¤šæ—¶é—´ï¼Œå¯æ˜¯æœ‰äº›
+ 虽然让眼ç›å’Œè„‘ç­‹æ¥é€‚应新的标准类型比如 “uint32_t†ä¸éœ€è¦èŠ±å¾ˆå¤šæ—¶é—´ï¼Œå¯æ˜¯æœ‰äº›
人ä»ç„¶æ‹’ç»ä½¿ç”¨å®ƒä»¬ã€‚
- 因此,Linux特有的等åŒäºŽæ ‡å‡†ç±»åž‹çš„“u8/u16/u32/u64â€ç±»åž‹å’Œå®ƒä»¬çš„æœ‰ç¬¦å·ç±»åž‹æ˜¯è¢«
+ 因此,Linux 特有的等åŒäºŽæ ‡å‡†ç±»åž‹çš„ “u8/u16/u32/u64†类型和它们的有符å·ç±»åž‹æ˜¯è¢«
å…许的——尽管在你自己的新代ç ä¸­ï¼Œå®ƒä»¬ä¸æ˜¯å¼ºåˆ¶è¦æ±‚è¦ä½¿ç”¨çš„。
当编辑已ç»ä½¿ç”¨äº†æŸä¸ªç±»åž‹é›†çš„å·²æœ‰ä»£ç æ—¶ï¼Œä½ åº”该éµå¾ªé‚£äº›ä»£ç ä¸­å·²ç»åšå‡ºçš„选择。
(e) å¯ä»¥åœ¨ç”¨æˆ·ç©ºé—´å®‰å…¨ä½¿ç”¨çš„类型。
- 在æŸäº›ç”¨æˆ·ç©ºé—´å¯è§çš„结构体里,我们ä¸èƒ½è¦æ±‚C99类型而且ä¸èƒ½ç”¨ä¸Šé¢æåˆ°çš„“u32â€
- 类型。因此,我们在与用户空间共享的所有结构体中使用__u32和类似的类型。
+ 在æŸäº›ç”¨æˆ·ç©ºé—´å¯è§çš„结构体里,我们ä¸èƒ½è¦æ±‚C99类型而且ä¸èƒ½ç”¨ä¸Šé¢æåˆ°çš„ “u32â€
+ 类型。因此,我们在与用户空间共享的所有结构体中使用 __u32 和类似的类型。
-å¯èƒ½è¿˜æœ‰å…¶ä»–的情况,ä¸è¿‡åŸºæœ¬çš„规则是永远ä¸è¦ä½¿ç”¨typedef,除éžä½ å¯ä»¥æ˜Žç¡®çš„应用上
+å¯èƒ½è¿˜æœ‰å…¶ä»–的情况,ä¸è¿‡åŸºæœ¬çš„规则是永远ä¸è¦ä½¿ç”¨ typedef,除éžä½ å¯ä»¥æ˜Žç¡®çš„应用上
è¿°æŸä¸ªè§„则中的一个。
总的æ¥è¯´ï¼Œå¦‚果一个指针或者一个结构体里的元素å¯ä»¥åˆç†çš„被直接访问到,那么它们就ä¸
-应该是一个typedef。
+应该是一个 typedef。
第六章:函数
函数应该简短而漂亮,并且åªå®Œæˆä¸€ä»¶äº‹æƒ…。函数应该å¯ä»¥ä¸€å±æˆ–è€…ä¸¤å±æ˜¾ç¤ºå®Œï¼ˆæˆ‘们都知
-é“ISO/ANSIå±å¹•大尿˜¯80x24),åªåšä¸€ä»¶äº‹æƒ…,而且把它åšå¥½ã€‚
+é“ ISO/ANSI å±å¹•大尿˜¯ 80x24),åªåšä¸€ä»¶äº‹æƒ…,而且把它åšå¥½ã€‚
ä¸€ä¸ªå‡½æ•°çš„æœ€å¤§é•¿åº¦æ˜¯å’Œè¯¥å‡½æ•°çš„å¤æ‚度和缩进级数æˆå比的。所以,如果你有一个ç†è®ºä¸Š
-很简å•çš„åªæœ‰ä¸€ä¸ªå¾ˆé•¿ï¼ˆä½†æ˜¯ç®€å•)的case语å¥çš„函数,而且你需è¦åœ¨æ¯ä¸ªcase里åšå¾ˆå¤šå¾ˆ
-å°çš„事情,这样的函数尽管很长,但也是å¯ä»¥çš„。
+很简å•çš„åªæœ‰ä¸€ä¸ªå¾ˆé•¿ï¼ˆä½†æ˜¯ç®€å•)的 case 语å¥çš„函数,而且你需è¦åœ¨æ¯ä¸ª case 里åš
+很多很å°çš„事情,这样的函数尽管很长,但也是å¯ä»¥çš„。
ä¸è¿‡ï¼Œå¦‚æžœä½ æœ‰ä¸€ä¸ªå¤æ‚çš„å‡½æ•°ï¼Œè€Œä¸”ä½ æ€€ç–‘ä¸€ä¸ªå¤©åˆ†ä¸æ˜¯å¾ˆé«˜çš„高中一年级学生å¯èƒ½ç”šè‡³
æžä¸æ¸…楚这个函数的目的,你应该严格的éµå®ˆå‰é¢æåˆ°çš„长度é™åˆ¶ã€‚使用辅助函数,并为之
å–个具æè¿°æ€§çš„å字(如果你觉得它们的性能很é‡è¦çš„è¯ï¼Œå¯ä»¥è®©ç¼–译器内è”它们,这样的
æ•ˆæžœå¾€å¾€ä¼šæ¯”ä½ å†™ä¸€ä¸ªå¤æ‚函数的效果è¦å¥½ã€‚)
-函数的å¦å¤–ä¸€ä¸ªè¡¡é‡æ ‡å‡†æ˜¯æœ¬åœ°å˜é‡çš„æ•°é‡ã€‚此数é‡ä¸åº”超过5ï¼10个,å¦åˆ™ä½ çš„函数就有
+函数的å¦å¤–ä¸€ä¸ªè¡¡é‡æ ‡å‡†æ˜¯æœ¬åœ°å˜é‡çš„æ•°é‡ã€‚此数é‡ä¸åº”超过 5ï¼10 个,å¦åˆ™ä½ çš„函数就有
é—®é¢˜äº†ã€‚é‡æ–°è€ƒè™‘ä¸€ä¸‹ä½ çš„å‡½æ•°ï¼ŒæŠŠå®ƒåˆ†æ‹†æˆæ›´å°çš„函数。人的大脑一般å¯ä»¥è½»æ¾çš„åŒæ—¶è·Ÿ
-踪7个ä¸åŒçš„事物,如果å†å¢žå¤šçš„è¯ï¼Œå°±ä¼šç³Šæ¶‚了。å³ä¾¿ä½ èªé¢–过人,你也å¯èƒ½ä¼šè®°ä¸æ¸…ä½ 2
-个星期å‰åšè¿‡çš„事情。
+踪 7 个ä¸åŒçš„事物,如果å†å¢žå¤šçš„è¯ï¼Œå°±ä¼šç³Šæ¶‚了。å³ä¾¿ä½ èªé¢–过人,你也å¯èƒ½ä¼šè®°ä¸æ¸…ä½ 
+2 个星期å‰åšè¿‡çš„事情。
-åœ¨æºæ–‡ä»¶é‡Œï¼Œä½¿ç”¨ç©ºè¡Œéš”å¼€ä¸åŒçš„函数。如果该函数需è¦è¢«å¯¼å‡ºï¼Œå®ƒçš„EXPORT*å®åº”该紧贴
+åœ¨æºæ–‡ä»¶é‡Œï¼Œä½¿ç”¨ç©ºè¡Œéš”å¼€ä¸åŒçš„函数。如果该函数需è¦è¢«å¯¼å‡ºï¼Œå®ƒçš„ EXPORT* å®åº”该紧贴
在它的结æŸå¤§æ‹¬å·ä¹‹ä¸‹ã€‚比如:
-int system_is_up(void)
-{
- return system_state == SYSTEM_RUNNING;
-}
-EXPORT_SYMBOL(system_is_up);
+ int system_is_up(void)
+ {
+ return system_state == SYSTEM_RUNNING;
+ }
+ EXPORT_SYMBOL(system_is_up);
-在函数原型中,包å«å‡½æ•°å和它们的数æ®ç±»åž‹ã€‚虽然Cè¯­è¨€é‡Œæ²¡æœ‰è¿™æ ·çš„è¦æ±‚,在Linux里这
+在函数原型中,包å«å‡½æ•°å和它们的数æ®ç±»åž‹ã€‚虽然Cè¯­è¨€é‡Œæ²¡æœ‰è¿™æ ·çš„è¦æ±‚,在 Linux 里这
是æå€¡çš„åšæ³•,因为这样å¯ä»¥å¾ˆç®€å•的给读者æä¾›æ›´å¤šçš„æœ‰ä»·å€¼çš„ä¿¡æ¯ã€‚
第七章:集中的函数退出途径
-虽然被æŸäº›äººå£°ç§°å·²ç»è¿‡æ—¶ï¼Œä½†æ˜¯goto语å¥çš„等价物还是ç»å¸¸è¢«ç¼–è¯‘å™¨æ‰€ä½¿ç”¨ï¼Œå…·ä½“å½¢å¼æ˜¯
+虽然被æŸäº›äººå£°ç§°å·²ç»è¿‡æ—¶ï¼Œä½†æ˜¯ goto 语å¥çš„等价物还是ç»å¸¸è¢«ç¼–è¯‘å™¨æ‰€ä½¿ç”¨ï¼Œå…·ä½“å½¢å¼æ˜¯
æ— æ¡ä»¶è·³è½¬æŒ‡ä»¤ã€‚
-当一个函数从多个ä½ç½®é€€å‡ºå¹¶ä¸”需è¦åšä¸€äº›é€šç”¨çš„æ¸…ç†å·¥ä½œçš„æ—¶å€™ï¼Œgoto的好处就显现出æ¥
-了。
+当一个函数从多个ä½ç½®é€€å‡ºï¼Œå¹¶ä¸”需è¦åšä¸€äº›ç±»ä¼¼æ¸…ç†çš„å¸¸è§æ“作时,goto 语å¥å°±å¾ˆæ–¹ä¾¿äº†ã€‚
+如果并ä¸éœ€è¦æ¸…ç†æ“作,那么直接 return å³å¯ã€‚
ç†ç”±æ˜¯ï¼š
@@ -354,26 +355,37 @@ EXPORT_SYMBOL(system_is_up);
- å¯ä»¥é¿å…由于修改时忘记更新æŸä¸ªå•独的退出点而导致的错误
- å‡è½»äº†ç¼–译器的工作,无需删除冗余代ç ;)
-int fun(int a)
-{
- int result = 0;
- char *buffer = kmalloc(SIZE);
-
- if (buffer == NULL)
- return -ENOMEM;
-
- if (condition1) {
- while (loop1) {
- ...
+ int fun(int a)
+ {
+ int result = 0;
+ char *buffer;
+
+ buffer = kmalloc(SIZE, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ if (condition1) {
+ while (loop1) {
+ ...
+ }
+ result = 1;
+ goto out_buffer;
}
- result = 1;
- goto out;
+ ...
+ out_buffer:
+ kfree(buffer);
+ return result;
}
- ...
-out:
- kfree(buffer);
- return result;
-}
+
+ä¸€ä¸ªéœ€è¦æ³¨æ„的常è§é”™è¯¯æ˜¯â€œä¸€ä¸ª err 错误â€ï¼Œå°±åƒè¿™æ ·ï¼š
+
+ err:
+ kfree(foo->bar);
+ kfree(foo);
+ return ret;
+
+这段代ç çš„错误是,在æŸäº›é€€å‡ºè·¯å¾„上 “foo†是 NULL。通常情况下,通过把它分离æˆä¸¤ä¸ª
+错误标签 “err_bar:†和 “err_foo:†æ¥ä¿®å¤è¿™ä¸ªé”™è¯¯ã€‚
第八章:注释
@@ -386,10 +398,10 @@ out:
加太多。你应该åšçš„,是把注释放在函数的头部,告诉人们它åšäº†ä»€ä¹ˆï¼Œä¹Ÿå¯ä»¥åŠ ä¸Šå®ƒåšè¿™
些事情的原因。
-当注释内核API函数时,请使用kernel-docæ ¼å¼ã€‚请看
-Documentation/kernel-doc-nano-HOWTO.txtå’Œscripts/kernel-doc以获得详细信æ¯ã€‚
+当注释内核API函数时,请使用 kernel-doc æ ¼å¼ã€‚请看
+Documentation/kernel-doc-nano-HOWTO.txtå’Œscripts/kernel-doc 以获得详细信æ¯ã€‚
-Linux的注释风格是C89“/* ... */â€é£Žæ ¼ã€‚ä¸è¦ä½¿ç”¨C99风格“// ...â€æ³¨é‡Šã€‚
+Linux的注释风格是 C89 “/* ... */†风格。ä¸è¦ä½¿ç”¨ C99 风格 “// ...†注释。
长(多行)的首选注释风格是:
@@ -402,6 +414,15 @@ Linux的注释风格是C89“/* ... */â€é£Žæ ¼ã€‚ä¸è¦ä½¿ç”¨C99风格“// ...
* with beginning and ending almost-blank lines.
*/
+对于在 net/ å’Œ drivers/net/ 的文件,首选的长(多行)注释风格有些ä¸åŒã€‚
+
+ /* The preferred comment style for files in net/ and drivers/net
+ * looks like this.
+ *
+ * It is nearly the same as the generally preferred comment style,
+ * but there is no initial almost-blank line.
+ */
+
注释数æ®ä¹Ÿæ˜¯å¾ˆé‡è¦çš„,ä¸ç®¡æ˜¯åŸºæœ¬ç±»åž‹è¿˜æ˜¯è¡ç”Ÿç±»åž‹ã€‚为了方便实现这一点,æ¯ä¸€è¡Œåº”åª
声明一个数æ®ï¼ˆä¸è¦ä½¿ç”¨é€—å·æ¥ä¸€æ¬¡å£°æ˜Žå¤šä¸ªæ•°æ®ï¼‰ã€‚这样你就有空间æ¥ä¸ºæ¯ä¸ªæ•°æ®å†™ä¸€æ®µ
å°æ³¨é‡Šæ¥è§£é‡Šå®ƒä»¬çš„用途了。
@@ -409,49 +430,63 @@ Linux的注释风格是C89“/* ... */â€é£Žæ ¼ã€‚ä¸è¦ä½¿ç”¨C99风格“// ...
第ä¹ç« ï¼šä½ å·²ç»æŠŠäº‹æƒ…弄糟了
-这没什么,我们都是这样。å¯èƒ½ä½ çš„使用了很长时间Unix的朋å‹å·²ç»å‘Šè¯‰ä½ â€œGNU emacsâ€èƒ½
-自动帮你格å¼åŒ–Cæºä»£ç ï¼Œè€Œä¸”你也注æ„到了,确实是这样,ä¸è¿‡å®ƒæ‰€ä½¿ç”¨çš„默认值和我们
-想è¦çš„ç›¸åŽ»ç”šè¿œï¼ˆå®žé™…ä¸Šï¼Œç”šè‡³æ¯”éšæœºæ‰“的还è¦å·®â€”—无数个猴å­åœ¨GNU emacs里打字永远ä¸
-会创造出一个好程åºï¼‰ï¼ˆè¯‘注:请å‚考Infinite Monkey Theorem)
-
-所以你è¦ä¹ˆæ”¾å¼ƒGNU emacs,è¦ä¹ˆæ”¹å˜å®ƒè®©å®ƒä½¿ç”¨æ›´åˆç†çš„设定。è¦é‡‡ç”¨åŽä¸€ä¸ªæ–¹æ¡ˆï¼Œä½ å¯
-以把下é¢è¿™æ®µç²˜è´´åˆ°ä½ çš„.emacs文件里。
-
-(defun linux-c-mode ()
- "C mode with adjusted defaults for use with the Linux kernel."
- (interactive)
- (c-mode)
- (c-set-style "K&R")
- (setq tab-width 8)
- (setq indent-tabs-mode t)
- (setq c-basic-offset 8))
-
-这样就定义了M-x linux-c-mode命令。当你hack一个模å—的时候,如果你把字符串
--*- linux-c -*-放在头两行的æŸä¸ªä½ç½®ï¼Œè¿™ä¸ªæ¨¡å¼å°†ä¼šè¢«è‡ªåŠ¨è°ƒç”¨ã€‚å¦‚æžœä½ å¸Œæœ›åœ¨ä½ ä¿®æ”¹
-/usr/src/linux里的文件时魔术般自动打开linux-c-modeçš„è¯ï¼Œä½ ä¹Ÿå¯èƒ½éœ€è¦æ·»åŠ 
-
-(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
- auto-mode-alist))
-
-到你的.emacs文件里。
-
-ä¸è¿‡å°±ç®—ä½ å°è¯•让emacs正确的格å¼åŒ–代ç å¤±è´¥äº†ï¼Œä¹Ÿå¹¶ä¸æ„味ç€ä½ å¤±åŽ»äº†ä¸€åˆ‡ï¼šè¿˜å¯ä»¥ç”¨â€œ
-indentâ€ã€‚
-
-ä¸è¿‡ï¼ŒGNU indent也有和GNU emacs一样有问题的设定,所以你需è¦ç»™å®ƒä¸€äº›å‘½ä»¤é€‰é¡¹ã€‚ä¸
-过,这还ä¸ç®—太糟糕,因为就算是GNU indent的作者也认åŒK&Rçš„æƒå¨æ€§ï¼ˆGNUçš„äººå¹¶ä¸æ˜¯å
-äººï¼Œä»–ä»¬åªæ˜¯åœ¨è¿™ä¸ªé—®é¢˜ä¸Šè¢«ä¸¥é‡çš„误导了),所以你åªè¦ç»™indent指定选项“-kr -i8â€
-(代表“K&R,8个字符缩进â€ï¼‰ï¼Œæˆ–者使用“scripts/Lindentâ€ï¼Œè¿™æ ·å°±å¯ä»¥ä»¥æœ€æ—¶é«¦çš„æ–¹å¼
+这没什么,我们都是这样。å¯èƒ½ä½ çš„使用了很长时间 Unix 的朋å‹å·²ç»å‘Šè¯‰ä½  “GNU emacs†能
+自动帮你格å¼åŒ– C æºä»£ç ï¼Œè€Œä¸”你也注æ„到了,确实是这样,ä¸è¿‡å®ƒæ‰€ä½¿ç”¨çš„默认值和我们
+想è¦çš„ç›¸åŽ»ç”šè¿œï¼ˆå®žé™…ä¸Šï¼Œç”šè‡³æ¯”éšæœºæ‰“的还è¦å·®â€”—无数个猴å­åœ¨ GNU emacs 里打字永远ä¸
+会创造出一个好程åºï¼‰ï¼ˆè¯‘注:请å‚考 Infinite Monkey Theorem)
+
+所以你è¦ä¹ˆæ”¾å¼ƒ GNU emacs,è¦ä¹ˆæ”¹å˜å®ƒè®©å®ƒä½¿ç”¨æ›´åˆç†çš„设定。è¦é‡‡ç”¨åŽä¸€ä¸ªæ–¹æ¡ˆï¼Œä½ å¯
+以把下é¢è¿™æ®µç²˜è´´åˆ°ä½ çš„ .emacs 文件里。
+
+(defun c-lineup-arglist-tabs-only (ignored)
+ "Line up argument lists by tabs, not spaces"
+ (let* ((anchor (c-langelem-pos c-syntactic-element))
+ (column (c-langelem-2nd-pos c-syntactic-element))
+ (offset (- (1+ column) anchor))
+ (steps (floor offset c-basic-offset)))
+ (* (max steps 1)
+ c-basic-offset)))
+
+(add-hook 'c-mode-common-hook
+ (lambda ()
+ ;; Add kernel style
+ (c-add-style
+ "linux-tabs-only"
+ '("linux" (c-offsets-alist
+ (arglist-cont-nonempty
+ c-lineup-gcc-asm-reg
+ c-lineup-arglist-tabs-only))))))
+
+(add-hook 'c-mode-hook
+ (lambda ()
+ (let ((filename (buffer-file-name)))
+ ;; Enable kernel mode for the appropriate files
+ (when (and filename
+ (string-match (expand-file-name "~/src/linux-trees")
+ filename))
+ (setq indent-tabs-mode t)
+ (setq show-trailing-whitespace t)
+ (c-set-style "linux-tabs-only")))))
+
+这会让 emacs 在 ~/src/linux-trees 目录下的 C æºæ–‡ä»¶èŽ·å¾—æ›´å¥½çš„å†…æ ¸ä»£ç é£Žæ ¼ã€‚
+
+ä¸è¿‡å°±ç®—ä½ å°è¯•让 emacs 正确的格å¼åŒ–代ç å¤±è´¥äº†ï¼Œä¹Ÿå¹¶ä¸æ„味ç€ä½ å¤±åŽ»äº†ä¸€åˆ‡ï¼šè¿˜å¯ä»¥ç”¨
+“indentâ€ã€‚
+
+ä¸è¿‡ï¼ŒGNU indent 也有和 GNU emacs 一样有问题的设定,所以你需è¦ç»™å®ƒä¸€äº›å‘½ä»¤é€‰é¡¹ã€‚ä¸
+过,这还ä¸ç®—太糟糕,因为就算是 GNU indent çš„ä½œè€…ä¹Ÿè®¤åŒ K&R çš„æƒå¨æ€§ï¼ˆGNU çš„äººå¹¶ä¸æ˜¯
+åäººï¼Œä»–ä»¬åªæ˜¯åœ¨è¿™ä¸ªé—®é¢˜ä¸Šè¢«ä¸¥é‡çš„误导了),所以你åªè¦ç»™ indent 指定选项 “-kr -i8â€
+(代表 “K&R,8 个字符缩进â€ï¼‰ï¼Œæˆ–者使用 “scripts/Lindentâ€ï¼Œè¿™æ ·å°±å¯ä»¥ä»¥æœ€æ—¶é«¦çš„æ–¹å¼
缩进æºä»£ç ã€‚
-“indentâ€æœ‰å¾ˆå¤šé€‰é¡¹ï¼Œç‰¹åˆ«æ˜¯é‡æ–°æ ¼å¼åŒ–注释的时候,你å¯èƒ½éœ€è¦çœ‹ä¸€ä¸‹å®ƒçš„æ‰‹å†Œé¡µã€‚ä¸è¿‡
-è®°ä½ï¼šâ€œindentâ€ä¸èƒ½ä¿®æ­£å的编程习惯。
+“indentâ€ æœ‰å¾ˆå¤šé€‰é¡¹ï¼Œç‰¹åˆ«æ˜¯é‡æ–°æ ¼å¼åŒ–注释的时候,你å¯èƒ½éœ€è¦çœ‹ä¸€ä¸‹å®ƒçš„æ‰‹å†Œé¡µã€‚ä¸è¿‡
+è®°ä½ï¼šâ€œindent†ä¸èƒ½ä¿®æ­£å的编程习惯。
- 第å章:Kconfigé…置文件
+ 第å章:Kconfig é…置文件
-对于é布æºç æ ‘的所有Kconfig*é…置文件æ¥è¯´ï¼Œå®ƒä»¬ç¼©è¿›æ–¹å¼ä¸ŽC代ç ç›¸æ¯”有所ä¸åŒã€‚紧挨
-在“configâ€å®šä¹‰ä¸‹é¢çš„行缩进一个制表符,帮助信æ¯åˆ™å†å¤šç¼©è¿›2个空格。比如:
+对于é布æºç æ ‘的所有 Kconfig* é…置文件æ¥è¯´ï¼Œå®ƒä»¬ç¼©è¿›æ–¹å¼ä¸Ž C 代ç ç›¸æ¯”有所ä¸åŒã€‚紧挨
+在 “config†定义下é¢çš„行缩进一个制表符,帮助信æ¯åˆ™å†å¤šç¼©è¿› 2 个空格。比如:
config AUDIT
bool "Auditing support"
@@ -470,7 +505,7 @@ config ADFS_FS_RW
depends on ADFS_FS
...
-è¦æŸ¥çœ‹é…置文件的完整文档,请看Documentation/kbuild/kconfig-language.txt。
+è¦æŸ¥çœ‹é…置文件的完整文档,请看 Documentation/kbuild/kconfig-language.txt。
第å一章:数æ®ç»“æž„
@@ -489,11 +524,11 @@ config ADFS_FS_RW
很多数æ®ç»“构实际上有2级引用计数,它们通常有ä¸åŒâ€œç±»â€çš„用户。å­ç±»è®¡æ•°å™¨ç»Ÿè®¡å­ç±»ç”¨
户的数é‡ï¼Œæ¯å½“å­ç±»è®¡æ•°å™¨å‡è‡³é›¶æ—¶ï¼Œå…¨å±€è®¡æ•°å™¨å‡ä¸€ã€‚
-è¿™ç§â€œå¤šçº§å¼•用计数â€çš„例å­å¯ä»¥åœ¨å†…存管ç†ï¼ˆâ€œstruct mm_structâ€ï¼šmm_userså’Œmm_count)
+è¿™ç§â€œå¤šçº§å¼•用计数â€çš„例å­å¯ä»¥åœ¨å†…存管ç†ï¼ˆâ€œstruct mm_structâ€ï¼šmm_users å’Œ mm_count)
和文件系统(“struct super_blockâ€ï¼šs_countå’Œs_active)中找到。
è®°ä½ï¼šå¦‚æžœå¦ä¸€ä¸ªæ‰§è¡Œçº¿ç´¢å¯ä»¥æ‰¾åˆ°ä½ çš„æ•°æ®ç»“构,但是这个数æ®ç»“构没有引用计数器,这
-里几乎肯定是一个bug。
+里几乎肯定是一个 bug。
第å二章:å®ï¼Œæžšä¸¾å’ŒRTL
@@ -508,102 +543,128 @@ config ADFS_FS_RW
一般的,如果能写æˆå†…è”函数就ä¸è¦å†™æˆåƒå‡½æ•°çš„å®ã€‚
-嫿œ‰å¤šä¸ªè¯­å¥çš„å®åº”该被包å«åœ¨ä¸€ä¸ªdo-while代ç å—里:
+嫿œ‰å¤šä¸ªè¯­å¥çš„å®åº”该被包å«åœ¨ä¸€ä¸ª do-while 代ç å—里:
-#define macrofun(a, b, c) \
- do { \
- if (a == 5) \
- do_this(b, c); \
- } while (0)
+ #define macrofun(a, b, c) \
+ do { \
+ if (a == 5) \
+ do_this(b, c); \
+ } while (0)
使用å®çš„æ—¶å€™åº”é¿å…的事情:
1) å½±å“æŽ§åˆ¶æµç¨‹çš„å®ï¼š
-#define FOO(x) \
- do { \
- if (blah(x) < 0) \
- return -EBUGGERED; \
- } while(0)
+ #define FOO(x) \
+ do { \
+ if (blah(x) < 0) \
+ return -EBUGGERED; \
+ } while (0)
éžå¸¸ä¸å¥½ã€‚它看起æ¥åƒä¸€ä¸ªå‡½æ•°ï¼Œä¸è¿‡å´èƒ½å¯¼è‡´â€œè°ƒç”¨â€å®ƒçš„函数退出;ä¸è¦æ‰“乱读者大脑里
的语法分æžå™¨ã€‚
2) ä¾èµ–于一个固定å字的本地å˜é‡çš„å®ï¼š
-#define FOO(val) bar(index, val)
+ #define FOO(val) bar(index, val)
å¯èƒ½çœ‹èµ·æ¥åƒæ˜¯ä¸ªä¸é”™çš„东西,ä¸è¿‡å®ƒéžå¸¸å®¹æ˜“把读代ç çš„人æžç³Šæ¶‚,而且容易导致看起æ¥
ä¸ç›¸å…³çš„æ”¹åЍ另æ¥é”™è¯¯ã€‚
-3) ä½œä¸ºå·¦å€¼çš„å¸¦å‚æ•°çš„å®ï¼š FOO(x) = y;如果有人把FOOå˜æˆä¸€ä¸ªå†…è”函数的è¯ï¼Œè¿™ç§ç”¨
+3) ä½œä¸ºå·¦å€¼çš„å¸¦å‚æ•°çš„å®ï¼š FOO(x) = y;如果有人把 FOO å˜æˆä¸€ä¸ªå†…è”函数的è¯ï¼Œè¿™ç§ç”¨
法就会出错了。
4) 忘记了优先级:使用表达å¼å®šä¹‰å¸¸é‡çš„å®å¿…须将表达å¼ç½®äºŽä¸€å¯¹å°æ‹¬å·ä¹‹å†…ã€‚å¸¦å‚æ•°çš„
å®ä¹Ÿè¦æ³¨æ„此类问题。
-#define CONSTANT 0x4000
-#define CONSTEXP (CONSTANT | 3)
+ #define CONSTANT 0x4000
+ #define CONSTEXP (CONSTANT | 3)
+
+5) 在å®é‡Œå®šä¹‰ç±»ä¼¼å‡½æ•°çš„æœ¬åœ°å˜é‡æ—¶å‘½å冲çªï¼š
-cpp手册对å®çš„讲解很详细。Gcc internals手册也详细讲解了RTL(译注:register
+ #define FOO(x) \
+ ({ \
+ typeof(x) ret; \
+ ret = calc_ret(x); \
+ (ret); \
+ })
+
+ret 是本地å˜é‡çš„通用åå­— - __foo_ret æ›´ä¸å®¹æ˜“与一个已存在的å˜é‡å†²çªã€‚
+
+cpp 手册对å®çš„讲解很详细。gcc internals 手册也详细讲解了 RTL(译注:register
transfer language),内核里的汇编语言ç»å¸¸ç”¨åˆ°å®ƒã€‚
第å三章:打å°å†…核消æ¯
内核开å‘者应该是å—过良好教育的。请一定注æ„内核信æ¯çš„æ‹¼å†™ï¼Œä»¥ç»™äººä»¥å¥½çš„å°è±¡ã€‚ä¸è¦
-用ä¸è§„范的å•è¯æ¯”如“dontâ€ï¼Œè€Œè¦ç”¨â€œdo notâ€æˆ–者“don'tâ€ã€‚ä¿è¯è¿™äº›ä¿¡æ¯ç®€å•ã€æ˜Žäº†ã€æ— 
-歧义。
+用ä¸è§„范的å•è¯æ¯”如 “dontâ€ï¼Œè€Œè¦ç”¨ “do notâ€æˆ–者 “don'tâ€ã€‚ä¿è¯è¿™äº›ä¿¡æ¯ç®€å•ã€æ˜Žäº†ã€
+无歧义。
内核信æ¯ä¸å¿…以å¥å·ï¼ˆè¯‘注:英文å¥å·ï¼Œå³ç‚¹ï¼‰ç»“æŸã€‚
-åœ¨å°æ‹¬å·é‡Œæ‰“å°æ•°å­—(%d)没有任何价值,应该é¿å…这样åšã€‚
+åœ¨å°æ‹¬å·é‡Œæ‰“å°æ•°å­— (%d) 没有任何价值,应该é¿å…这样åšã€‚
-<linux/device.h>里有一些驱动模型诊断å®ï¼Œä½ åº”该使用它们,以确ä¿ä¿¡æ¯å¯¹åº”于正确的
-设备和驱动,并且被标记了正确的消æ¯çº§åˆ«ã€‚è¿™äº›å®æœ‰ï¼šdev_err(), dev_warn(),
-dev_info()等等。对于那些ä¸å’ŒæŸä¸ªç‰¹å®šè®¾å¤‡ç›¸å…³è¿žçš„ä¿¡æ¯ï¼Œ<linux/kernel.h>定义了
-pr_debug()和pr_info()。
+<linux/device.h> 里有一些驱动模型诊断å®ï¼Œä½ åº”该使用它们,以确ä¿ä¿¡æ¯å¯¹åº”于正确的
+设备和驱动,并且被标记了正确的消æ¯çº§åˆ«ã€‚è¿™äº›å®æœ‰ï¼šdev_err(),dev_warn(),
+dev_info() 等等。对于那些ä¸å’ŒæŸä¸ªç‰¹å®šè®¾å¤‡ç›¸å…³è¿žçš„ä¿¡æ¯ï¼Œ<linux/printk.h> 定义了
+pr_notice(),pr_info(),pr_warn(),pr_err() 和其他。
-写出好的调试信æ¯å¯ä»¥æ˜¯ä¸€ä¸ªå¾ˆå¤§çš„æŒ‘战;当你写出æ¥ä¹‹åŽï¼Œè¿™äº›ä¿¡æ¯åœ¨è¿œç¨‹é™¤é”™çš„æ—¶å€™
-就会æˆä¸ºæžå¤§çš„帮助。当DEBUGç¬¦å·æ²¡æœ‰è¢«å®šä¹‰çš„æ—¶å€™ï¼Œè¿™äº›ä¿¡æ¯ä¸åº”该被编译进内核里
-(也就是说,默认地,它们ä¸åº”该被包å«åœ¨å†…)。如果你使用dev_dbg()或者pr_debug(),
-就能自动达到这个效果。很多å­ç³»ç»Ÿæ‹¥æœ‰Kconfig选项æ¥å¯ç”¨-DDEBUG。还有一个相关的惯例
-是使用VERBOSE_DEBUGæ¥æ·»åŠ dev_vdbg()消æ¯åˆ°é‚£äº›å·²ç»ç”±DEBUGå¯ç”¨çš„æ¶ˆæ¯ä¹‹ä¸Šã€‚
+写出好的调试信æ¯å¯ä»¥æ˜¯ä¸€ä¸ªå¾ˆå¤§çš„æŒ‘战;一旦你写出åŽï¼Œè¿™äº›ä¿¡æ¯åœ¨è¿œç¨‹é™¤é”™æ—¶èƒ½æä¾›æžå¤§
+的帮助。然而打å°è°ƒè¯•ä¿¡æ¯çš„å¤„ç†æ–¹å¼åŒæ‰“å°éžè°ƒè¯•ä¿¡æ¯ä¸åŒã€‚å…¶ä»– pr_XXX() 函数能无æ¡ä»¶åœ°
+打å°ï¼Œpr_debug() å´ä¸ï¼›é»˜è®¤æƒ…况下它ä¸ä¼šè¢«ç¼–译,除éžå®šä¹‰äº† DEBUG 或设定了
+CONFIG_DYNAMIC_DEBUGã€‚å®žé™…è¿™åŒæ ·æ˜¯ä¸ºäº† dev_dbg(),一个相关约定是在一个已ç»å¼€å¯äº†
+DEBUG 时,使用 VERBOSE_DEBUG æ¥æ·»åŠ  dev_vdbg()。
+
+许多å­ç³»ç»Ÿæ‹¥æœ‰ Kconfig 调试选项æ¥å¼€å¯ -DDEBUG 在对应的 Makefile 里é¢ï¼›åœ¨å…¶ä»–
+情况下,特殊文件使用 #define DEBUG。当一æ¡è°ƒè¯•ä¿¡æ¯éœ€è¦è¢«æ— æ¡ä»¶æ‰“å°æ—¶ï¼Œä¾‹å¦‚,如果
+å·²ç»åŒ…å«ä¸€ä¸ªè°ƒè¯•相关的 #ifdef æ¡ä»¶ï¼Œprintk(KERN_DEBUG ...) å°±å¯è¢«ä½¿ç”¨ã€‚
第å四章:分é…内存
-内核æä¾›äº†ä¸‹é¢çš„一般用途的内存分é…函数:kmalloc(),kzalloc(),kcalloc()å’Œ
-vmalloc()。请å‚考APIæ–‡æ¡£ä»¥èŽ·å–æœ‰å…³å®ƒä»¬çš„详细信æ¯ã€‚
+内核æä¾›äº†ä¸‹é¢çš„一般用途的内存分é…函数:
+kmalloc(),kzalloc(),kmalloc_array(),kcalloc(),vmalloc() 和 vzalloc()。
+请å‚考 API æ–‡æ¡£ä»¥èŽ·å–æœ‰å…³å®ƒä»¬çš„详细信æ¯ã€‚
传递结构体大å°çš„首选形弿˜¯è¿™æ ·çš„:
p = kmalloc(sizeof(*p), ...);
-å¦å¤–一ç§ä¼ é€’æ–¹å¼ä¸­ï¼Œsizeofçš„æ“作数是结构体的å字,这样会é™ä½Žå¯è¯»æ€§ï¼Œå¹¶ä¸”å¯èƒ½ä¼šå¼•
-å…¥bug。有å¯èƒ½æŒ‡é’ˆå˜é‡ç±»åž‹è¢«æ”¹å˜æ—¶ï¼Œè€Œå¯¹åº”的传递给内存分é…函数的sizeof的结果ä¸å˜ã€‚
+å¦å¤–一ç§ä¼ é€’æ–¹å¼ä¸­ï¼Œsizeof çš„æ“作数是结构体的å字,这样会é™ä½Žå¯è¯»æ€§ï¼Œå¹¶ä¸”å¯èƒ½ä¼šå¼•
+å…¥ bug。有å¯èƒ½æŒ‡é’ˆå˜é‡ç±»åž‹è¢«æ”¹å˜æ—¶ï¼Œè€Œå¯¹åº”的传递给内存分é…函数的 sizeof 的结果ä¸å˜ã€‚
-强制转æ¢ä¸€ä¸ªvoid指针返回值是多余的。C语言本身ä¿è¯äº†ä»Žvoid指针到其他任何指针类型
+强制转æ¢ä¸€ä¸ª void 指针返回值是多余的。C 语言本身ä¿è¯äº†ä»Ž void 指针到其他任何指针类型
çš„è½¬æ¢æ˜¯æ²¡æœ‰é—®é¢˜çš„。
+分é…ä¸€ä¸ªæ•°ç»„çš„é¦–é€‰å½¢å¼æ˜¯è¿™æ ·çš„:
+
+ p = kmalloc_array(n, sizeof(...), ...);
+
+分é…ä¸€ä¸ªé›¶é•¿æ•°ç»„çš„é¦–é€‰å½¢å¼æ˜¯è¿™æ ·çš„:
+
+ p = kcalloc(n, sizeof(...), ...);
+
+两ç§å½¢å¼æ£€æŸ¥åˆ†é…å¤§å° n * sizeof(...) 的溢出,如果溢出返回 NULL。
+
第å五章:内è”弊病
-有一个常è§çš„误解是内è”函数是gccæä¾›çš„å¯ä»¥è®©ä»£ç è¿è¡Œæ›´å¿«çš„一个选项。虽然使用内è”
+有一个常è§çš„误解是内è”函数是 gcc æä¾›çš„å¯ä»¥è®©ä»£ç è¿è¡Œæ›´å¿«çš„一个选项。虽然使用内è”
函数有时候是æ°å½“çš„ï¼ˆæ¯”å¦‚ä½œä¸ºä¸€ç§æ›¿ä»£å®çš„æ–¹å¼ï¼Œè¯·çœ‹ç¬¬å二章),ä¸è¿‡å¾ˆå¤šæƒ…况䏋䏿˜¯
-这样。inline关键字的过度使用会使内核å˜å¤§ï¼Œä»Žè€Œä½¿æ•´ä¸ªç³»ç»Ÿè¿è¡Œé€Ÿåº¦å˜æ…¢ã€‚因为大内核
+这样。inline 关键字的过度使用会使内核å˜å¤§ï¼Œä»Žè€Œä½¿æ•´ä¸ªç³»ç»Ÿè¿è¡Œé€Ÿåº¦å˜æ…¢ã€‚因为大内核
会å ç”¨æ›´å¤šçš„æŒ‡ä»¤é«˜é€Ÿç¼“存(译注:一级缓存通常是指令缓存和数æ®ç¼“存分开的)而且会导
-致pagecacheçš„å¯ç”¨å†…å­˜å‡å°‘。想象一下,一次pagecache未命中就会导致一次ç£ç›˜å¯»å€ï¼Œå°†
-耗时5毫秒。5毫秒的时间内CPU能执行很多很多指令。
+致 pagecache çš„å¯ç”¨å†…å­˜å‡å°‘。想象一下,一次pagecache未命中就会导致一次ç£ç›˜å¯»å€ï¼Œ
+将耗时 5 毫秒。5 毫秒的时间内 CPU 能执行很多很多指令。
-一个基本的原则是如果一个函数有3行以上,就ä¸è¦æŠŠå®ƒå˜æˆå†…è”函数。这个原则的一个例
+一个基本的原则是如果一个函数有 3 行以上,就ä¸è¦æŠŠå®ƒå˜æˆå†…è”函数。这个原则的一个例
å¤–æ˜¯ï¼Œå¦‚æžœä½ çŸ¥é“æŸä¸ªå‚数是一个编译时常é‡ï¼Œè€Œä¸”因为这个常é‡ä½ ç¡®å®šç¼–译器在编译时能
-优化掉你的函数的大部分代ç ï¼Œé‚£ä»ç„¶å¯ä»¥ç»™å®ƒåŠ ä¸Šinline关键字。kmalloc()内è”函数就
+优化掉你的函数的大部分代ç ï¼Œé‚£ä»ç„¶å¯ä»¥ç»™å®ƒåŠ ä¸Š inline 关键字。kmalloc() 内è”函数就
是一个很好的例å­ã€‚
-人们ç»å¸¸ä¸»å¼ ç»™static的而且åªç”¨äº†ä¸€æ¬¡çš„函数加上inline,如此ä¸ä¼šæœ‰ä»»ä½•æŸå¤±ï¼Œå› ä¸ºæ²¡
-有什么好æƒè¡¡çš„ã€‚è™½ç„¶ä»ŽæŠ€æœ¯ä¸Šè¯´è¿™æ˜¯æ­£ç¡®çš„ï¼Œä½†æ˜¯å®žé™…ä¸Šè¿™ç§æƒ…况下å³ä½¿ä¸åŠ inline gcc
-也å¯ä»¥è‡ªåŠ¨ä½¿å…¶å†…è”。而且其他用户å¯èƒ½ä¼šè¦æ±‚移除inline,由此而æ¥çš„争论会抵消inline
+人们ç»å¸¸ä¸»å¼ ç»™ static 的而且åªç”¨äº†ä¸€æ¬¡çš„函数加上 inline,如此ä¸ä¼šæœ‰ä»»ä½•æŸå¤±ï¼Œå› ä¸ºæ²¡
+有什么好æƒè¡¡çš„ã€‚è™½ç„¶ä»ŽæŠ€æœ¯ä¸Šè¯´è¿™æ˜¯æ­£ç¡®çš„ï¼Œä½†æ˜¯å®žé™…ä¸Šè¿™ç§æƒ…况下å³ä½¿ä¸åŠ  inline gcc
+也å¯ä»¥è‡ªåŠ¨ä½¿å…¶å†…è”。而且其他用户å¯èƒ½ä¼šè¦æ±‚移除 inline,由此而æ¥çš„争论会抵消 inline
自身的潜在价值,得ä¸å¿å¤±ã€‚
@@ -613,37 +674,37 @@ vmalloc()。请å‚考APIæ–‡æ¡£ä»¥èŽ·å–æœ‰å…³å®ƒä»¬çš„详细信æ¯ã€‚
的一个值å¯ä»¥è¡¨ç¤ºä¸ºä¸€ä¸ªé”™è¯¯ä»£ç æ•´æ•°ï¼ˆ-Exxxï¼å¤±è´¥ï¼Œ0ï¼æˆåŠŸï¼‰æˆ–è€…ä¸€ä¸ªâ€œæˆåŠŸâ€å¸ƒå°”值(
0ï¼å¤±è´¥ï¼Œéž0ï¼æˆåŠŸï¼‰ã€‚
-æ··åˆä½¿ç”¨è¿™ä¸¤ç§è¡¨è¾¾æ–¹å¼æ˜¯éš¾äºŽå‘现的bugçš„æ¥æºã€‚如果C语言本身严格区分整形和布尔型å˜
-é‡ï¼Œé‚£ä¹ˆç¼–译器就能够帮我们å‘现这些错误……ä¸è¿‡C语言ä¸åŒºåˆ†ã€‚为了é¿å…产生这ç§bug,请
+æ··åˆä½¿ç”¨è¿™ä¸¤ç§è¡¨è¾¾æ–¹å¼æ˜¯éš¾äºŽå‘现的 bug çš„æ¥æºã€‚如果 C 语言本身严格区分整形和布尔型å˜
+é‡ï¼Œé‚£ä¹ˆç¼–译器就能够帮我们å‘现这些错误……ä¸è¿‡ C 语言ä¸åŒºåˆ†ã€‚为了é¿å…äº§ç”Ÿè¿™ç§ bug,请
éµå¾ªä¸‹é¢çš„æƒ¯ä¾‹ï¼š
如果函数的åå­—æ˜¯ä¸€ä¸ªåŠ¨ä½œæˆ–è€…å¼ºåˆ¶æ€§çš„å‘½ä»¤ï¼Œé‚£ä¹ˆè¿™ä¸ªå‡½æ•°åº”è¯¥è¿”å›žé”™è¯¯ä»£ç æ•´
数。如果是一个判断,那么函数应该返回一个“æˆåŠŸâ€å¸ƒå°”值。
-比如,“add workâ€æ˜¯ä¸€ä¸ªå‘½ä»¤ï¼Œæ‰€ä»¥add_work()函数在æˆåŠŸæ—¶è¿”å›ž0,在失败时返回-EBUSY。
-类似的,因为“PCI device presentâ€æ˜¯ä¸€ä¸ªåˆ¤æ–­ï¼Œæ‰€ä»¥pci_dev_present()函数在æˆåŠŸæ‰¾åˆ°
-一个匹é…的设备时应该返回1,如果找ä¸åˆ°æ—¶åº”该返回0。
+比如,“add work†是一个命令,所以 add_work() 函数在æˆåŠŸæ—¶è¿”å›ž 0,在失败时返回 -EBUSY。
+类似的,因为 “PCI device present†是一个判断,所以 pci_dev_present() 函数在æˆåŠŸæ‰¾åˆ°
+一个匹é…的设备时应该返回 1,如果找ä¸åˆ°æ—¶åº”该返回 0。
所有导出(译注:EXPORT)的函数都必须éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ï¼Œæ‰€æœ‰çš„公共函数也都应该如此。ç§
有(static)函数ä¸éœ€è¦å¦‚此,但是我们也推è这样åšã€‚
è¿”å›žå€¼æ˜¯å®žé™…è®¡ç®—ç»“æžœè€Œä¸æ˜¯è®¡ç®—æ˜¯å¦æˆåŠŸçš„æ ‡å¿—çš„å‡½æ•°ä¸å—此惯例的é™åˆ¶ã€‚一般的,他们
通过返回一些正常值范围之外的结果æ¥è¡¨ç¤ºå‡ºé”™ã€‚å…¸åž‹çš„ä¾‹å­æ˜¯è¿”回指针的函数,他们使用
-NULL或者ERR_PTRæœºåˆ¶æ¥æŠ¥å‘Šé”™è¯¯ã€‚
+NULL 或者 ERR_PTR æœºåˆ¶æ¥æŠ¥å‘Šé”™è¯¯ã€‚
第å七章:ä¸è¦é‡æ–°å‘明内核å®
-头文件include/linux/kernel.h包å«äº†ä¸€äº›å®ï¼Œä½ åº”该使用它们,而ä¸è¦è‡ªå·±å†™ä¸€äº›å®ƒä»¬çš„
+头文件 include/linux/kernel.h 包å«äº†ä¸€äº›å®ï¼Œä½ åº”该使用它们,而ä¸è¦è‡ªå·±å†™ä¸€äº›å®ƒä»¬çš„
å˜ç§ã€‚比如,如果你需è¦è®¡ç®—一个数组的长度,使用这个å®
- #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
类似的,如果你è¦è®¡ç®—æŸç»“构体æˆå‘˜çš„大å°ï¼Œä½¿ç”¨
- #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+ #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
-还有å¯ä»¥åšä¸¥æ ¼çš„类型检查的min()å’Œmax()å®ï¼Œå¦‚果你需è¦å¯ä»¥ä½¿ç”¨å®ƒä»¬ã€‚ä½ å¯ä»¥è‡ªå·±çœ‹çœ‹
+还有å¯ä»¥åšä¸¥æ ¼çš„类型检查的 min() å’Œ max() å®ï¼Œå¦‚果你需è¦å¯ä»¥ä½¿ç”¨å®ƒä»¬ã€‚ä½ å¯ä»¥è‡ªå·±çœ‹çœ‹
那个头文件里还定义了什么你å¯ä»¥æ‹¿æ¥ç”¨çš„东西,如果有定义的è¯ï¼Œä½ å°±ä¸åº”在你的代ç é‡Œ
è‡ªå·±é‡æ–°å®šä¹‰ã€‚
@@ -653,42 +714,100 @@ NULL或者ERR_PTRæœºåˆ¶æ¥æŠ¥å‘Šé”™è¯¯ã€‚
有一些编辑器å¯ä»¥è§£é‡ŠåµŒå…¥åœ¨æºæ–‡ä»¶é‡Œçš„由一些特殊标记标明的é…置信æ¯ã€‚比如,emacs
能够解释被标记æˆè¿™æ ·çš„行:
--*- mode: c -*-
+ -*- mode: c -*-
或者这样的:
-/*
-Local Variables:
-compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
-End:
-*/
+ /*
+ Local Variables:
+ compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
+ End:
+ */
-Vim能够解释这样的标记:
+Vim 能够解释这样的标记:
-/* vim:set sw=8 noet */
+ /* vim:set sw=8 noet */
ä¸è¦åœ¨æºä»£ç ä¸­åŒ…å«ä»»ä½•这样的内容。æ¯ä¸ªäººéƒ½æœ‰ä»–自己的编辑器é…ç½®ï¼Œä½ çš„æºæ–‡ä»¶ä¸åº”
该覆盖别人的é…置。这包括有关缩进和模å¼é…置的标记。人们å¯ä»¥ä½¿ç”¨ä»–们自己定制的模
å¼ï¼Œæˆ–者使用其他å¯ä»¥äº§ç”Ÿæ­£ç¡®çš„缩进的巧妙方法。
+ 第åä¹ç« ï¼šå†…è”æ±‡ç¼–
+
+在特定架构的代ç ä¸­ï¼Œä½ ä¹Ÿè®¸éœ€è¦å†…è”æ±‡ç¼–æ¥ä½¿ç”¨ CPU 接å£å’Œå¹³å°ç›¸å…³åŠŸèƒ½ã€‚åœ¨éœ€è¦
+è¿™ä¹ˆåšæ—¶ï¼Œä¸è¦çŠ¹è±«ã€‚ç„¶è€Œï¼Œå½“ C å¯ä»¥å®Œæˆå·¥ä½œæ—¶ï¼Œä¸è¦æ— ç«¯åœ°ä½¿ç”¨å†…è”æ±‡ç¼–。如果
+å¯èƒ½ï¼Œä½ å¯ä»¥å¹¶ä¸”应该用 C 和硬件交互。
+
+è€ƒè™‘åŽ»å†™é€šç”¨ä¸€ç‚¹çš„å†…è”æ±‡ç¼–ä½œä¸ºç®€æ˜Žçš„è¾…åŠ©å‡½æ•°ï¼Œè€Œä¸æ˜¯é‡å¤å†™ä¸‹å®ƒä»¬çš„细节。记ä½
+å†…è”æ±‡ç¼–å¯ä»¥ä½¿ç”¨ C 傿•°ã€‚
+
+大而特殊的汇编函数应该放在 .S 文件中,对应 C 的原型定义在 C 头文件中。汇编
+函数的 C 原型应该使用 “asmlinkageâ€ã€‚
+
+ä½ å¯èƒ½éœ€è¦å°†ä½ çš„æ±‡ç¼–è¯­å¥æ ‡è®°ä¸º volatile,æ¥é˜»æ­¢ GCC 在没å‘现任何副作用åŽå°±
+移除了它。你ä¸å¿…总是这样åšï¼Œè™½ç„¶ï¼Œè¿™æ ·å¯ä»¥é™åˆ¶ä¸å¿…è¦çš„优化。
+
+在写一个包å«å¤šæ¡æŒ‡ä»¤çš„å•ä¸ªå†…è”æ±‡ç¼–è¯­å¥æ—¶ï¼ŒæŠŠæ¯æ¡æŒ‡ä»¤ç”¨å¼•å·å­—符串分离,并写在
+å•独一行,在æ¯ä¸ªå­—符串结尾,除了 \n\t 结尾之外,在汇编输出中适当地缩进下
+ä¸€æ¡æŒ‡ä»¤ï¼š
+
+ asm ("magic %reg1, #42\n\t"
+ "more_magic %reg2, %reg3"
+ : /* outputs */ : /* inputs */ : /* clobbers */);
+
+
+ 第二å章:æ¡ä»¶ç¼–译
+
+åªè¦å¯èƒ½ï¼Œå°±ä¸è¦åœ¨ .c 文件里é¢ä½¿ç”¨é¢„å¤„ç†æ¡ä»¶ï¼›è¿™æ ·åšè®©ä»£ç æ›´éš¾é˜…读并且逻辑难以
+跟踪。替代方案是,在头文件定义函数在这些 .c 文件中使用这类的æ¡ä»¶è¡¨è¾¾å¼ï¼Œæä¾›ç©º
+æ“作的桩版本(译注:桩程åºï¼Œæ˜¯æŒ‡ç”¨æ¥æ›¿æ¢ä¸€éƒ¨åˆ†åŠŸèƒ½çš„ç¨‹åºæ®µï¼‰åœ¨ #else 情况下,
+å†ä»Ž .c 文件中无æ¡ä»¶åœ°è°ƒç”¨è¿™äº›å‡½æ•°ã€‚编译器会é¿å…生æˆä»»ä½•桩调用的代ç ï¼Œäº§ç”Ÿä¸€è‡´
+的结果,但逻辑将更加清晰。
+
+å®å¯ç¼–è¯‘æ•´ä¸ªå‡½æ•°ï¼Œè€Œä¸æ˜¯éƒ¨åˆ†å‡½æ•°æˆ–部分表达å¼ã€‚è€Œä¸æ˜¯åœ¨ä¸€ä¸ªè¡¨è¾¾å¼æ·»åŠ  ifdef,
+è§£æžéƒ¨åˆ†æˆ–全部表达å¼åˆ°ä¸€ä¸ªå•独的辅助函数,并应用æ¡ä»¶åˆ°è¯¥å‡½æ•°å†…。
+
+如果你有一个在特定é…置中å¯èƒ½æ˜¯æœªä½¿ç”¨çš„函数或å˜é‡ï¼Œç¼–译器将警告它定义了但未使用,
+标记这个定义为 __maybe_unused è€Œä¸æ˜¯å°†å®ƒåŒ…å«åœ¨ä¸€ä¸ªé¢„å¤„ç†æ¡ä»¶ä¸­ã€‚(然而,如果
+一个函数或å˜é‡æ€»æ˜¯æœªä½¿ç”¨çš„,就直接删除它。)
+
+在代ç ä¸­ï¼Œå¯èƒ½çš„æƒ…况下,使用 IS_ENABLED 宿¥è½¬åŒ–æŸä¸ª Kconfig 标记为 C 的布尔
+表达å¼ï¼Œå¹¶åœ¨æ­£å¸¸çš„ C æ¡ä»¶ä¸­ä½¿ç”¨å®ƒï¼š
+
+ if (IS_ENABLED(CONFIG_SOMETHING)) {
+ ...
+ }
+
+编译器会无æ¡ä»¶åœ°åšå¸¸æ•°åˆå¹¶ï¼Œå°±åƒä½¿ç”¨ #ifdef é‚£æ ·ï¼ŒåŒ…å«æˆ–排除代ç å—,所以这ä¸ä¼š
+带æ¥ä»»ä½•è¿è¡Œæ—¶å¼€é”€ã€‚ç„¶è€Œï¼Œè¿™ç§æ–¹æ³•便—§å…许 C 编译器查看å—内的代ç ï¼Œå¹¶æ£€æŸ¥å®ƒçš„æ­£ç¡®
+性(语法,类型,符å·å¼•用,等等)。因此,如果æ¡ä»¶ä¸æ»¡è¶³ï¼Œä»£ç å—内的引用符å·å°†ä¸å­˜åœ¨ï¼Œ
+你必须继续使用 #ifdef。
+
+在任何有æ„义的 #if 或 #ifdef å—的末尾(超过几行),在 #endif åŒä¸€è¡Œçš„åŽé¢å†™ä¸‹
+注释,指出该æ¡ä»¶è¡¨è¾¾å¼è¢«ä½¿ç”¨ã€‚例如:
+
+ #ifdef CONFIG_SOMETHING
+ ...
+ #endif /* CONFIG_SOMETHING */
+
附录 I:å‚考
-The C Programming Language, 第二版, 作者Brian W. Kernighan和Denni
-M. Ritchie. Prentice Hall, Inc., 1988. ISBN 0-13-110362-8 (软皮),
-0-13-110370-9 (硬皮). URL: http://cm.bell-labs.com/cm/cs/cbook/
+The C Programming Language, 第二版
+作者:Brian W. Kernighan 和 Denni M. Ritchie.
+Prentice Hall, Inc., 1988.
+ISBN 0-13-110362-8 (软皮), 0-13-110370-9 (硬皮).
-The Practice of Programming 作者Brian W. Kernighan和Rob Pike. Addison-Wesley,
-Inc., 1999. ISBN 0-201-61586-X. URL: http://cm.bell-labs.com/cm/cs/tpop/
+The Practice of Programming
+作者:Brian W. Kernighan 和 Rob Pike.
+Addison-Wesley, Inc., 1999.
+ISBN 0-201-61586-X.
-cpp,gcc,gcc internalså’Œindentçš„GNU手册——和K&RåŠæœ¬æ–‡ç›¸ç¬¦åˆçš„部分,全部å¯ä»¥åœ¨
-http://www.gnu.org/manual/找到
+GNU 手册 - éµå¾ª K&R 标准和此文本 - cpp, gcc, gcc internals and indent,
+都å¯ä»¥ä»Ž http://www.gnu.org/manual/ 找到
WG14是C语言的国际标准化工作组,URL: http://www.open-std.org/JTC1/SC22/WG14/
-Kernel CodingStyle,作者greg@kroah.comå‘表于OLS 2002:
+Kernel CodingStyle,作者 greg@kroah.com å‘表于OLS 2002:
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
-
---
-æœ€åŽæ›´æ–°äºŽ2007å¹´7月13日。
diff --git a/Makefile b/Makefile
index 8d1301ab59fd..801457b847a4 100644
--- a/Makefile
+++ b/Makefile
@@ -1412,8 +1412,11 @@ $(help-board-dirs): help-%:
# Documentation targets
# ---------------------------------------------------------------------------
-%docs: scripts_basic FORCE
+DOC_TARGETS := xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs epubdocs cleandocs
+PHONY += $(DOC_TARGETS)
+$(DOC_TARGETS): scripts_basic FORCE
$(Q)$(MAKE) $(build)=scripts build_docproc build_check-lc_ctype
+ $(Q)$(MAKE) $(build)=Documentation -f $(srctree)/Documentation/Makefile.sphinx $@
$(Q)$(MAKE) $(build)=Documentation/DocBook $@
else # KBUILD_EXTMOD
diff --git a/arch/arc/boot/dts/nsimosci.dts b/arch/arc/boot/dts/nsimosci.dts
index b5b060adce8a..37c416defe90 100644
--- a/arch/arc/boot/dts/nsimosci.dts
+++ b/arch/arc/boot/dts/nsimosci.dts
@@ -20,7 +20,7 @@
/* this is for console on PGU */
/* bootargs = "console=tty0 consoleblank=0"; */
/* this is for console on serial */
- bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug";
+ bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24";
};
aliases {
@@ -58,9 +58,17 @@
no-loopback-test = <1>;
};
- pgu0: pgu@f9000000 {
- compatible = "snps,arcpgufb";
+ pguclk: pguclk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <25175000>;
+ };
+
+ pgu@f9000000 {
+ compatible = "snps,arcpgu";
reg = <0xf9000000 0x400>;
+ clocks = <&pguclk>;
+ clock-names = "pxlclk";
};
ps2: ps2@f9001000 {
diff --git a/arch/arc/boot/dts/nsimosci_hs.dts b/arch/arc/boot/dts/nsimosci_hs.dts
index 325e73090a18..f2a22c49541d 100644
--- a/arch/arc/boot/dts/nsimosci_hs.dts
+++ b/arch/arc/boot/dts/nsimosci_hs.dts
@@ -20,7 +20,7 @@
/* this is for console on PGU */
/* bootargs = "console=tty0 consoleblank=0"; */
/* this is for console on serial */
- bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug";
+ bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24";
};
aliases {
@@ -58,9 +58,17 @@
no-loopback-test = <1>;
};
- pgu0: pgu@f9000000 {
- compatible = "snps,arcpgufb";
+ pguclk: pguclk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <25175000>;
+ };
+
+ pgu@f9000000 {
+ compatible = "snps,arcpgu";
reg = <0xf9000000 0x400>;
+ clocks = <&pguclk>;
+ clock-names = "pxlclk";
};
ps2: ps2@f9001000 {
diff --git a/arch/arc/boot/dts/nsimosci_hs_idu.dts b/arch/arc/boot/dts/nsimosci_hs_idu.dts
index ee03d7126581..34457a5e7706 100644
--- a/arch/arc/boot/dts/nsimosci_hs_idu.dts
+++ b/arch/arc/boot/dts/nsimosci_hs_idu.dts
@@ -18,7 +18,7 @@
chosen {
/* this is for console on serial */
- bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblan=0 debug";
+ bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblan=0 debug video=640x480-24";
};
aliases {
@@ -77,9 +77,17 @@
no-loopback-test = <1>;
};
- pgu0: pgu@f9000000 {
- compatible = "snps,arcpgufb";
+ pguclk: pguclk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <25175000>;
+ };
+
+ pgu@f9000000 {
+ compatible = "snps,arcpgu";
reg = <0xf9000000 0x400>;
+ clocks = <&pguclk>;
+ clock-names = "pxlclk";
};
ps2: ps2@f9001000 {
diff --git a/arch/arc/boot/dts/vdk_axs10x_mb.dtsi b/arch/arc/boot/dts/vdk_axs10x_mb.dtsi
index 45cd665fca23..99498a4b4216 100644
--- a/arch/arc/boot/dts/vdk_axs10x_mb.dtsi
+++ b/arch/arc/boot/dts/vdk_axs10x_mb.dtsi
@@ -23,6 +23,11 @@
#clock-cells = <0>;
};
+ pguclk: pguclk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <25175000>;
+ };
};
ethernet@0x18000 {
@@ -75,11 +80,11 @@
};
/* PGU output directly sent to virtual LCD screen; hdmi controller not modelled */
- pgu@0x17000 {
- compatible = "snps,arcpgufb";
+ pgu@17000 {
+ compatible = "snps,arcpgu";
reg = <0x17000 0x400>;
- clock-frequency = <51000000>; /* PGU'clock is initated in init function */
- /* interrupts = <5>; PGU interrupts not used, this vector is used for ps2 below */
+ clocks = <&pguclk>;
+ clock-names = "pxlclk";
};
/* VDK has additional ps2 keyboard/mouse interface integrated in LCD screen model */
diff --git a/arch/arc/boot/dts/vdk_hs38_smp.dts b/arch/arc/boot/dts/vdk_hs38_smp.dts
index 031a5bc79b3e..2ba60c399d99 100644
--- a/arch/arc/boot/dts/vdk_hs38_smp.dts
+++ b/arch/arc/boot/dts/vdk_hs38_smp.dts
@@ -16,6 +16,6 @@
compatible = "snps,axs103";
chosen {
- bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0";
+ bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0 video=640x480-24";
};
};
diff --git a/arch/arc/configs/nsimosci_defconfig b/arch/arc/configs/nsimosci_defconfig
index 42bafa552498..98cf20933bbb 100644
--- a/arch/arc/configs/nsimosci_defconfig
+++ b/arch/arc/configs/nsimosci_defconfig
@@ -58,7 +58,8 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=1
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
-CONFIG_FB=y
+CONFIG_DRM=y
+CONFIG_DRM_ARCPGU=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
# CONFIG_HID is not set
diff --git a/arch/arc/configs/nsimosci_hs_defconfig b/arch/arc/configs/nsimosci_hs_defconfig
index 4bb60c1cd4a2..ddf8b96d494e 100644
--- a/arch/arc/configs/nsimosci_hs_defconfig
+++ b/arch/arc/configs/nsimosci_hs_defconfig
@@ -57,7 +57,8 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=1
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
-CONFIG_FB=y
+CONFIG_DRM=y
+CONFIG_DRM_ARCPGU=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
# CONFIG_HID is not set
diff --git a/arch/arc/configs/nsimosci_hs_smp_defconfig b/arch/arc/configs/nsimosci_hs_smp_defconfig
index 7e88f4c720f8..ceb90745326e 100644
--- a/arch/arc/configs/nsimosci_hs_smp_defconfig
+++ b/arch/arc/configs/nsimosci_hs_smp_defconfig
@@ -70,7 +70,8 @@ CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
-CONFIG_FB=y
+CONFIG_DRM=y
+CONFIG_DRM_ARCPGU=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
# CONFIG_HID is not set
diff --git a/arch/arc/configs/vdk_hs38_smp_defconfig b/arch/arc/configs/vdk_hs38_smp_defconfig
index 52ec315dc5c9..969b206d6c67 100644
--- a/arch/arc/configs/vdk_hs38_smp_defconfig
+++ b/arch/arc/configs/vdk_hs38_smp_defconfig
@@ -63,12 +63,9 @@ CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
-CONFIG_FB=y
-CONFIG_ARCPGU_RGB888=y
-CONFIG_ARCPGU_DISPTYPE=0
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_DRM=y
+CONFIG_DRM_ARCPGU=y
CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
diff --git a/drivers/gpu/drm/arc/Makefile b/drivers/gpu/drm/arc/Makefile
index d48fda70f857..73de56a0139a 100644
--- a/drivers/gpu/drm/arc/Makefile
+++ b/drivers/gpu/drm/arc/Makefile
@@ -1,2 +1,2 @@
-arcpgu-y := arcpgu_crtc.o arcpgu_hdmi.o arcpgu_drv.o
+arcpgu-y := arcpgu_crtc.o arcpgu_hdmi.o arcpgu_sim.o arcpgu_drv.o
obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o
diff --git a/drivers/gpu/drm/arc/arcpgu.h b/drivers/gpu/drm/arc/arcpgu.h
index 8c01a25d279a..e8fcf3ab1d9a 100644
--- a/drivers/gpu/drm/arc/arcpgu.h
+++ b/drivers/gpu/drm/arc/arcpgu.h
@@ -42,6 +42,7 @@ static inline u32 arc_pgu_read(struct arcpgu_drm_private *arcpgu,
int arc_pgu_setup_crtc(struct drm_device *dev);
int arcpgu_drm_hdmi_init(struct drm_device *drm, struct device_node *np);
+int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np);
struct drm_fbdev_cma *arcpgu_fbdev_cma_init(struct drm_device *dev,
unsigned int preferred_bpp, unsigned int num_crtc,
unsigned int max_conn_count);
diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c
index a92e533531c3..381c5fcbf903 100644
--- a/drivers/gpu/drm/arc/arcpgu_drv.c
+++ b/drivers/gpu/drm/arc/arcpgu_drv.c
@@ -125,15 +125,16 @@ static int arcpgu_load(struct drm_device *drm)
/* find the encoder node and initialize it */
encoder_node = of_parse_phandle(drm->dev->of_node, "encoder-slave", 0);
- if (!encoder_node) {
- dev_err(drm->dev, "failed to get an encoder slave node\n");
- return -ENODEV;
+ if (encoder_node) {
+ ret = arcpgu_drm_hdmi_init(drm, encoder_node);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = arcpgu_drm_sim_init(drm, 0);
+ if (ret < 0)
+ return ret;
}
- ret = arcpgu_drm_hdmi_init(drm, encoder_node);
- if (ret < 0)
- return ret;
-
drm_mode_config_reset(drm);
drm_kms_helper_poll_init(drm);
diff --git a/drivers/gpu/drm/arc/arcpgu_sim.c b/drivers/gpu/drm/arc/arcpgu_sim.c
new file mode 100644
index 000000000000..2bf06d71556a
--- /dev/null
+++ b/drivers/gpu/drm/arc/arcpgu_sim.c
@@ -0,0 +1,128 @@
+/*
+ * ARC PGU DRM driver.
+ *
+ * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "arcpgu.h"
+
+#define XRES_DEF 640
+#define YRES_DEF 480
+
+#define XRES_MAX 8192
+#define YRES_MAX 8192
+
+
+struct arcpgu_drm_connector {
+ struct drm_connector connector;
+ struct drm_encoder_slave *encoder_slave;
+};
+
+static int arcpgu_drm_connector_get_modes(struct drm_connector *connector)
+{
+ int count;
+
+ count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
+ drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);
+ return count;
+}
+
+static enum drm_connector_status
+arcpgu_drm_connector_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static void arcpgu_drm_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_helper_funcs
+arcpgu_drm_connector_helper_funcs = {
+ .get_modes = arcpgu_drm_connector_get_modes,
+};
+
+static const struct drm_connector_funcs arcpgu_drm_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .reset = drm_atomic_helper_connector_reset,
+ .detect = arcpgu_drm_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = arcpgu_drm_connector_destroy,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static struct drm_encoder_funcs arcpgu_drm_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np)
+{
+ struct arcpgu_drm_connector *arcpgu_connector;
+ struct drm_encoder_slave *encoder;
+ struct drm_connector *connector;
+ int ret;
+
+ encoder = devm_kzalloc(drm->dev, sizeof(*encoder), GFP_KERNEL);
+ if (encoder == NULL)
+ return -ENOMEM;
+
+ encoder->base.possible_crtcs = 1;
+ encoder->base.possible_clones = 0;
+
+ ret = drm_encoder_init(drm, &encoder->base, &arcpgu_drm_encoder_funcs,
+ DRM_MODE_ENCODER_VIRTUAL, NULL);
+ if (ret)
+ return ret;
+
+ arcpgu_connector = devm_kzalloc(drm->dev, sizeof(*arcpgu_connector),
+ GFP_KERNEL);
+ if (!arcpgu_connector) {
+ ret = -ENOMEM;
+ goto error_encoder_cleanup;
+ }
+
+ connector = &arcpgu_connector->connector;
+ drm_connector_helper_add(connector, &arcpgu_drm_connector_helper_funcs);
+
+ ret = drm_connector_init(drm, connector, &arcpgu_drm_connector_funcs,
+ DRM_MODE_CONNECTOR_VIRTUAL);
+ if (ret < 0) {
+ dev_err(drm->dev, "failed to initialize drm connector\n");
+ goto error_encoder_cleanup;
+ }
+
+ ret = drm_mode_connector_attach_encoder(connector, &encoder->base);
+ if (ret < 0) {
+ dev_err(drm->dev, "could not attach connector to encoder\n");
+ drm_connector_unregister(connector);
+ goto error_connector_cleanup;
+ }
+
+ arcpgu_connector->encoder_slave = encoder;
+
+ return 0;
+
+error_connector_cleanup:
+ drm_connector_cleanup(connector);
+
+error_encoder_cleanup:
+ drm_encoder_cleanup(&encoder->base);
+ return ret;
+}
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 6a13df8691d4..de7fddce3cef 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1324,8 +1324,8 @@ static int stall_checks(struct drm_crtc *crtc, bool nonblock)
} else if (i == 1) {
stall_commit = commit;
drm_crtc_commit_get(stall_commit);
- } else
break;
+ }
i++;
}
@@ -1337,7 +1337,7 @@ static int stall_checks(struct drm_crtc *crtc, bool nonblock)
/* We don't want to let commits get ahead of cleanup work too much,
* stalling on 2nd previous commit means triple-buffer won't ever stall.
*/
- ret = wait_for_completion_interruptible_timeout(&commit->cleanup_done,
+ ret = wait_for_completion_interruptible_timeout(&stall_commit->cleanup_done,
10*HZ);
if (ret == 0)
DRM_ERROR("[CRTC:%d:%s] cleanup_done timed out\n",
@@ -1579,11 +1579,8 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *state)
/* commit_list borrows our reference, need to remove before we
* clean up our drm_atomic_state. But only after it actually
* completed, otherwise subsequent commits won't stall properly. */
- if (try_wait_for_completion(&commit->flip_done)) {
- list_del(&commit->commit_entry);
- spin_unlock(&crtc->commit_lock);
- continue;
- }
+ if (try_wait_for_completion(&commit->flip_done))
+ goto del_commit;
spin_unlock(&crtc->commit_lock);
@@ -1597,6 +1594,7 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *state)
crtc->base.id, crtc->name);
spin_lock(&crtc->commit_lock);
+del_commit:
list_del(&commit->commit_entry);
spin_unlock(&crtc->commit_lock);
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
index 67cebb23c940..aa04fb0159a7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
@@ -293,13 +293,10 @@ static int vmw_cmdbuf_header_submit(struct vmw_cmdbuf_header *header)
struct vmw_cmdbuf_man *man = header->man;
u32 val;
- if (sizeof(header->handle) > 4)
- val = (header->handle >> 32);
- else
- val = 0;
+ val = upper_32_bits(header->handle);
vmw_write(man->dev_priv, SVGA_REG_COMMAND_HIGH, val);
- val = (header->handle & 0xFFFFFFFFULL);
+ val = lower_32_bits(header->handle);
val |= header->cb_context & SVGA_CB_CONTEXT_MASK;
vmw_write(man->dev_priv, SVGA_REG_COMMAND_LOW, val);
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 2fc8fad5195e..27757c21551a 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -59,6 +59,12 @@ Output format selection (mutually exclusive):
-text Output plain text format.
Output selection (mutually exclusive):
+ -export Only output documentation for symbols that have been
+ exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL()
+ in the same FILE.
+ -internal Only output documentation for symbols that have NOT been
+ exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL()
+ in the same FILE.
-function NAME Only output documentation for the given function(s)
or DOC: section title(s). All other functions and DOC:
sections are ignored. May be specified multiple times.
@@ -68,6 +74,8 @@ Output selection (mutually exclusive):
Output selection modifiers:
-no-doc-sections Do not output DOC: sections.
+ -enable-lineno Enable output of #define LINENO lines. Only works with
+ reStructuredText format.
Other parameters:
-v Verbose output, more warnings and other information.
@@ -206,6 +214,10 @@ my $type_struct_xml = '\\&amp;((struct\s*)*[_\w]+)';
my $type_env = '(\$\w+)';
my $type_enum_full = '\&(enum)\s*([_\w]+)';
my $type_struct_full = '\&(struct)\s*([_\w]+)';
+my $type_typedef_full = '\&(typedef)\s*([_\w]+)';
+my $type_union_full = '\&(union)\s*([_\w]+)';
+my $type_member = '\&([_\w]+)((\.|->)[_\w]+)';
+my $type_member_func = $type_member . '\(\)';
# Output conversion substitutions.
# One for each output format
@@ -274,10 +286,16 @@ my $blankline_text = "";
# rst-mode
my @highlights_rst = (
[$type_constant, "``\$1``"],
- [$type_func, "\\:c\\:func\\:`\$1`"],
+ # Note: need to escape () to avoid func matching later
+ [$type_member_func, "\\:c\\:type\\:`\$1\$2\\\\(\\\\) <\$1>`"],
+ [$type_member, "\\:c\\:type\\:`\$1\$2 <\$1>`"],
+ [$type_func, "\\:c\\:func\\:`\$1()`"],
[$type_struct_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"],
[$type_enum_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"],
- [$type_struct, "\\:c\\:type\\:`struct \$1 <\$1>`"],
+ [$type_typedef_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"],
+ [$type_union_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"],
+ # in rst this can refer to any type
+ [$type_struct, "\\:c\\:type\\:`\$1`"],
[$type_param, "**\$1**"]
);
my $blankline_rst = "\n";
@@ -303,10 +321,19 @@ my $verbose = 0;
my $output_mode = "man";
my $output_preformatted = 0;
my $no_doc_sections = 0;
+my $enable_lineno = 0;
my @highlights = @highlights_man;
my $blankline = $blankline_man;
my $modulename = "Kernel API";
-my $function_only = 0;
+
+use constant {
+ OUTPUT_ALL => 0, # output all symbols and doc sections
+ OUTPUT_INCLUDE => 1, # output only specified symbols
+ OUTPUT_EXCLUDE => 2, # output everything except specified symbols
+ OUTPUT_EXPORTED => 3, # output exported symbols
+ OUTPUT_INTERNAL => 4, # output non-exported symbols
+};
+my $output_selection = OUTPUT_ALL;
my $show_not_found = 0;
my @build_time;
@@ -327,6 +354,7 @@ my $man_date = ('January', 'February', 'March', 'April', 'May', 'June',
# CAVEAT EMPTOR! Some of the others I localised may not want to be, which
# could cause "use of undefined value" or other bugs.
my ($function, %function_table, %parametertypes, $declaration_purpose);
+my $declaration_start_line;
my ($type, $declaration_name, $return_type);
my ($newsection, $newcontents, $prototype, $brcount, %source_map);
@@ -344,52 +372,62 @@ my $section_counter = 0;
my $lineprefix="";
-# states
-# 0 - normal code
-# 1 - looking for function name
-# 2 - scanning field start.
-# 3 - scanning prototype.
-# 4 - documentation block
-# 5 - gathering documentation outside main block
+# Parser states
+use constant {
+ STATE_NORMAL => 0, # normal code
+ STATE_NAME => 1, # looking for function name
+ STATE_FIELD => 2, # scanning field start
+ STATE_PROTO => 3, # scanning prototype
+ STATE_DOCBLOCK => 4, # documentation block
+ STATE_INLINE => 5, # gathering documentation outside main block
+};
my $state;
my $in_doc_sect;
-# Split Doc State
-# 0 - Invalid (Before start or after finish)
-# 1 - Is started (the /** was found inside a struct)
-# 2 - The @parameter header was found, start accepting multi paragraph text.
-# 3 - Finished (the */ was found)
-# 4 - Error - Comment without header was found. Spit a warning as it's not
-# proper kernel-doc and ignore the rest.
-my $split_doc_state;
+# Inline documentation state
+use constant {
+ STATE_INLINE_NA => 0, # not applicable ($state != STATE_INLINE)
+ STATE_INLINE_NAME => 1, # looking for member name (@foo:)
+ STATE_INLINE_TEXT => 2, # looking for member documentation
+ STATE_INLINE_END => 3, # done
+ STATE_INLINE_ERROR => 4, # error - Comment without header was found.
+ # Spit a warning as it's not
+ # proper kernel-doc and ignore the rest.
+};
+my $inline_doc_state;
#declaration types: can be
# 'function', 'struct', 'union', 'enum', 'typedef'
my $decl_type;
-my $doc_special = "\@\%\$\&";
-
my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start.
my $doc_end = '\*/';
my $doc_com = '\s*\*\s*';
my $doc_com_body = '\s*\* ?';
my $doc_decl = $doc_com . '(\w+)';
-my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)';
+# @params and a strictly limited set of supported section names
+my $doc_sect = $doc_com .
+ '\s*(\@\w+|description|context|returns?|notes?|examples?)\s*:(.*)';
my $doc_content = $doc_com_body . '(.*)';
my $doc_block = $doc_com . 'DOC:\s*(.*)?';
-my $doc_split_start = '^\s*/\*\*\s*$';
-my $doc_split_sect = '\s*\*\s*(@[\w\s]+):(.*)';
-my $doc_split_end = '^\s*\*/\s*$';
+my $doc_inline_start = '^\s*/\*\*\s*$';
+my $doc_inline_sect = '\s*\*\s*(@[\w\s]+):(.*)';
+my $doc_inline_end = '^\s*\*/\s*$';
+my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;';
-my %constants;
my %parameterdescs;
+my %parameterdesc_start_lines;
my @parameterlist;
my %sections;
my @sectionlist;
+my %section_start_lines;
my $sectcheck;
my $struct_actual;
my $contents = "";
+my $new_start_line = 0;
+
+# the canonical section names. see also $doc_sect above.
my $section_default = "Description"; # default section
my $section_intro = "Introduction";
my $section = $section_default;
@@ -437,19 +475,27 @@ while ($ARGV[0] =~ m/^-(.*)/) {
} elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document
$modulename = shift @ARGV;
} elsif ($cmd eq "-function") { # to only output specific functions
- $function_only = 1;
+ $output_selection = OUTPUT_INCLUDE;
$function = shift @ARGV;
$function_table{$function} = 1;
- } elsif ($cmd eq "-nofunction") { # to only output specific functions
- $function_only = 2;
+ } elsif ($cmd eq "-nofunction") { # output all except specific functions
+ $output_selection = OUTPUT_EXCLUDE;
$function = shift @ARGV;
$function_table{$function} = 1;
+ } elsif ($cmd eq "-export") { # only exported symbols
+ $output_selection = OUTPUT_EXPORTED;
+ %function_table = ()
+ } elsif ($cmd eq "-internal") { # only non-exported symbols
+ $output_selection = OUTPUT_INTERNAL;
+ %function_table = ()
} elsif ($cmd eq "-v") {
$verbose = 1;
} elsif (($cmd eq "-h") || ($cmd eq "--help")) {
usage();
} elsif ($cmd eq '-no-doc-sections') {
$no_doc_sections = 1;
+ } elsif ($cmd eq '-enable-lineno') {
+ $enable_lineno = 1;
} elsif ($cmd eq '-show-not-found') {
$show_not_found = 1;
}
@@ -467,6 +513,13 @@ sub get_kernel_version() {
return $version;
}
+#
+sub print_lineno {
+ my $lineno = shift;
+ if ($enable_lineno && defined($lineno)) {
+ print "#define LINENO " . $lineno . "\n";
+ }
+}
##
# dumps section contents to arrays/hashes intended for that purpose.
#
@@ -475,28 +528,32 @@ sub dump_section {
my $name = shift;
my $contents = join "\n", @_;
- if ($name =~ m/$type_constant/) {
- $name = $1;
-# print STDERR "constant section '$1' = '$contents'\n";
- $constants{$name} = $contents;
- } elsif ($name =~ m/$type_param/) {
+ if ($name =~ m/$type_param/) {
# print STDERR "parameter def '$1' = '$contents'\n";
$name = $1;
$parameterdescs{$name} = $contents;
$sectcheck = $sectcheck . $name . " ";
+ $parameterdesc_start_lines{$name} = $new_start_line;
+ $new_start_line = 0;
} elsif ($name eq "@\.\.\.") {
# print STDERR "parameter def '...' = '$contents'\n";
$name = "...";
$parameterdescs{$name} = $contents;
$sectcheck = $sectcheck . $name . " ";
+ $parameterdesc_start_lines{$name} = $new_start_line;
+ $new_start_line = 0;
} else {
# print STDERR "other section '$name' = '$contents'\n";
if (defined($sections{$name}) && ($sections{$name} ne "")) {
- print STDERR "${file}:$.: error: duplicate section name '$name'\n";
- ++$errors;
+ print STDERR "${file}:$.: warning: duplicate section name '$name'\n";
+ ++$warnings;
+ $sections{$name} .= $contents;
+ } else {
+ $sections{$name} = $contents;
+ push @sectionlist, $name;
+ $section_start_lines{$name} = $new_start_line;
+ $new_start_line = 0;
}
- $sections{$name} = $contents;
- push @sectionlist, $name;
}
}
@@ -512,15 +569,17 @@ sub dump_doc_section {
return;
}
- if (($function_only == 0) ||
- ( $function_only == 1 && defined($function_table{$name})) ||
- ( $function_only == 2 && !defined($function_table{$name})))
+ if (($output_selection == OUTPUT_ALL) ||
+ ($output_selection == OUTPUT_INCLUDE &&
+ defined($function_table{$name})) ||
+ ($output_selection == OUTPUT_EXCLUDE &&
+ !defined($function_table{$name})))
{
dump_section($file, $name, $contents);
output_blockhead({'sectionlist' => \@sectionlist,
'sections' => \%sections,
'module' => $modulename,
- 'content-only' => ($function_only != 0), });
+ 'content-only' => ($output_selection != OUTPUT_ALL), });
}
}
@@ -1736,7 +1795,10 @@ sub output_blockhead_rst(%) {
my ($parameter, $section);
foreach $section (@{$args{'sectionlist'}}) {
- print "**$section**\n\n";
+ if ($output_selection != OUTPUT_INCLUDE) {
+ print "**$section**\n\n";
+ }
+ print_lineno($section_start_lines{$section});
output_highlight_rst($args{'sections'}{$section});
print "\n";
}
@@ -1753,19 +1815,14 @@ sub output_highlight_rst {
die $@ if $@;
foreach $line (split "\n", $contents) {
- if ($line eq "") {
- print $lineprefix, $blankline;
- } else {
- $line =~ s/\\\\\\/\&/g;
- print $lineprefix, $line;
- }
- print "\n";
+ print $lineprefix . $line . "\n";
}
}
sub output_function_rst(%) {
my %args = %{$_[0]};
my ($parameter, $section);
+ my $oldprefix = $lineprefix;
my $start;
print ".. c:function:: ";
@@ -1790,29 +1847,37 @@ sub output_function_rst(%) {
print $type . " " . $parameter;
}
}
- print ")\n\n " . $args{'purpose'} . "\n\n";
+ print ")\n\n";
+ print_lineno($declaration_start_line);
+ $lineprefix = " ";
+ output_highlight_rst($args{'purpose'});
+ print "\n";
- print ":Parameters:\n\n";
+ print "**Parameters**\n\n";
+ $lineprefix = " ";
foreach $parameter (@{$args{'parameterlist'}}) {
my $parameter_name = $parameter;
#$parameter_name =~ s/\[.*//;
$type = $args{'parametertypes'}{$parameter};
if ($type ne "") {
- print " ``$type $parameter``\n";
+ print "``$type $parameter``\n";
} else {
- print " ``$parameter``\n";
+ print "``$parameter``\n";
}
- if ($args{'parameterdescs'}{$parameter_name} ne $undescribed) {
- my $oldprefix = $lineprefix;
- $lineprefix = " ";
+
+ print_lineno($parameterdesc_start_lines{$parameter_name});
+
+ if (defined($args{'parameterdescs'}{$parameter_name}) &&
+ $args{'parameterdescs'}{$parameter_name} ne $undescribed) {
output_highlight_rst($args{'parameterdescs'}{$parameter_name});
- $lineprefix = $oldprefix;
} else {
- print "\n _undescribed_\n";
+ print " *undescribed*\n";
}
print "\n";
}
+
+ $lineprefix = $oldprefix;
output_section_rst(@_);
}
@@ -1820,10 +1885,11 @@ sub output_section_rst(%) {
my %args = %{$_[0]};
my $section;
my $oldprefix = $lineprefix;
- $lineprefix = " ";
+ $lineprefix = "";
foreach $section (@{$args{'sectionlist'}}) {
- print ":$section:\n\n";
+ print "**$section**\n\n";
+ print_lineno($section_start_lines{$section});
output_highlight_rst($args{'sections'}{$section});
print "\n";
}
@@ -1834,24 +1900,28 @@ sub output_section_rst(%) {
sub output_enum_rst(%) {
my %args = %{$_[0]};
my ($parameter);
+ my $oldprefix = $lineprefix;
my $count;
my $name = "enum " . $args{'enum'};
print "\n\n.. c:type:: " . $name . "\n\n";
- print " " . $args{'purpose'} . "\n\n";
+ print_lineno($declaration_start_line);
+ $lineprefix = " ";
+ output_highlight_rst($args{'purpose'});
+ print "\n";
- print "..\n\n:Constants:\n\n";
- my $oldprefix = $lineprefix;
- $lineprefix = " ";
+ print "**Constants**\n\n";
+ $lineprefix = " ";
foreach $parameter (@{$args{'parameterlist'}}) {
- print " `$parameter`\n";
+ print "``$parameter``\n";
if ($args{'parameterdescs'}{$parameter} ne $undescribed) {
output_highlight_rst($args{'parameterdescs'}{$parameter});
} else {
- print " undescribed\n";
+ print " *undescribed*\n";
}
print "\n";
}
+
$lineprefix = $oldprefix;
output_section_rst(@_);
}
@@ -1859,30 +1929,37 @@ sub output_enum_rst(%) {
sub output_typedef_rst(%) {
my %args = %{$_[0]};
my ($parameter);
- my $count;
+ my $oldprefix = $lineprefix;
my $name = "typedef " . $args{'typedef'};
- ### FIXME: should the name below contain "typedef" or not?
print "\n\n.. c:type:: " . $name . "\n\n";
- print " " . $args{'purpose'} . "\n\n";
+ print_lineno($declaration_start_line);
+ $lineprefix = " ";
+ output_highlight_rst($args{'purpose'});
+ print "\n";
+ $lineprefix = $oldprefix;
output_section_rst(@_);
}
sub output_struct_rst(%) {
my %args = %{$_[0]};
my ($parameter);
+ my $oldprefix = $lineprefix;
my $name = $args{'type'} . " " . $args{'struct'};
print "\n\n.. c:type:: " . $name . "\n\n";
- print " " . $args{'purpose'} . "\n\n";
+ print_lineno($declaration_start_line);
+ $lineprefix = " ";
+ output_highlight_rst($args{'purpose'});
+ print "\n";
- print ":Definition:\n\n";
- print " ::\n\n";
+ print "**Definition**\n\n";
+ print "::\n\n";
print " " . $args{'type'} . " " . $args{'struct'} . " {\n";
foreach $parameter (@{$args{'parameterlist'}}) {
if ($parameter =~ /^#/) {
- print " " . "$parameter\n";
+ print " " . "$parameter\n";
next;
}
@@ -1903,7 +1980,8 @@ sub output_struct_rst(%) {
}
print " };\n\n";
- print ":Members:\n\n";
+ print "**Members**\n\n";
+ $lineprefix = " ";
foreach $parameter (@{$args{'parameterlist'}}) {
($parameter =~ /^#/) && next;
@@ -1912,14 +1990,14 @@ sub output_struct_rst(%) {
($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
$type = $args{'parametertypes'}{$parameter};
- print " `$type $parameter`" . "\n";
- my $oldprefix = $lineprefix;
- $lineprefix = " ";
+ print_lineno($parameterdesc_start_lines{$parameter_name});
+ print "``$type $parameter``\n";
output_highlight_rst($args{'parameterdescs'}{$parameter_name});
- $lineprefix = $oldprefix;
print "\n";
}
print "\n";
+
+ $lineprefix = $oldprefix;
output_section_rst(@_);
}
@@ -1969,9 +2047,13 @@ sub output_declaration {
my $name = shift;
my $functype = shift;
my $func = "output_${functype}_$output_mode";
- if (($function_only==0) ||
- ( $function_only == 1 && defined($function_table{$name})) ||
- ( $function_only == 2 && !($functype eq "function" && defined($function_table{$name}))))
+ if (($output_selection == OUTPUT_ALL) ||
+ (($output_selection == OUTPUT_INCLUDE ||
+ $output_selection == OUTPUT_EXPORTED) &&
+ defined($function_table{$name})) ||
+ (($output_selection == OUTPUT_EXCLUDE ||
+ $output_selection == OUTPUT_INTERNAL) &&
+ !($functype eq "function" && defined($function_table{$name}))))
{
&$func(@_);
$section_counter++;
@@ -2471,7 +2553,6 @@ sub dump_function($$) {
sub reset_state {
$function = "";
- %constants = ();
%parameterdescs = ();
%parametertypes = ();
@parameterlist = ();
@@ -2481,8 +2562,8 @@ sub reset_state {
$struct_actual = "";
$prototype = "";
- $state = 0;
- $split_doc_state = 0;
+ $state = STATE_NORMAL;
+ $inline_doc_state = STATE_INLINE_NA;
}
sub tracepoint_munge($) {
@@ -2545,7 +2626,7 @@ sub syscall_munge() {
}
}
-sub process_state3_function($$) {
+sub process_proto_function($$) {
my $x = shift;
my $file = shift;
@@ -2575,7 +2656,7 @@ sub process_state3_function($$) {
}
}
-sub process_state3_type($$) {
+sub process_proto_type($$) {
my $x = shift;
my $file = shift;
@@ -2657,6 +2738,7 @@ sub process_file($) {
my $in_purpose = 0;
my $initial_section_counter = $section_counter;
my ($orig_file) = @_;
+ my $leading_space;
if (defined($ENV{'SRCTREE'})) {
$file = "$ENV{'SRCTREE'}" . "/" . $orig_file;
@@ -2674,6 +2756,17 @@ sub process_file($) {
return;
}
+ # two passes for -export and -internal
+ if ($output_selection == OUTPUT_EXPORTED ||
+ $output_selection == OUTPUT_INTERNAL) {
+ while (<IN>) {
+ if (/$export_symbol/o) {
+ $function_table{$2} = 1;
+ }
+ }
+ seek(IN, 0, 0);
+ }
+
$. = 1;
$section_counter = 0;
@@ -2681,15 +2774,18 @@ sub process_file($) {
while (s/\\\s*$//) {
$_ .= <IN>;
}
- if ($state == 0) {
+ if ($state == STATE_NORMAL) {
if (/$doc_start/o) {
- $state = 1; # next line is always the function name
+ $state = STATE_NAME; # next line is always the function name
$in_doc_sect = 0;
+ $declaration_start_line = $. + 1;
}
- } elsif ($state == 1) { # this line is the function name (always)
+ } elsif ($state == STATE_NAME) {# this line is the function name (always)
if (/$doc_block/o) {
- $state = 4;
+ $state = STATE_DOCBLOCK;
$contents = "";
+ $new_start_line = $. + 1;
+
if ( $1 eq "" ) {
$section = $section_intro;
} else {
@@ -2702,7 +2798,12 @@ sub process_file($) {
$identifier = $1;
}
- $state = 2;
+ $state = STATE_FIELD;
+ # if there's no @param blocks need to set up default section
+ # here
+ $contents = "";
+ $section = $section_default;
+ $new_start_line = $. + 1;
if (/-(.*)/) {
# strip leading/trailing/multiple spaces
$descr= $1;
@@ -2740,13 +2841,25 @@ sub process_file($) {
print STDERR "${file}:$.: warning: Cannot understand $_ on line $.",
" - I thought it was a doc line\n";
++$warnings;
- $state = 0;
+ $state = STATE_NORMAL;
}
- } elsif ($state == 2) { # look for head: lines, and include content
- if (/$doc_sect/o) {
+ } elsif ($state == STATE_FIELD) { # look for head: lines, and include content
+ if (/$doc_sect/i) { # case insensitive for supported section names
$newsection = $1;
$newcontents = $2;
+ # map the supported section names to the canonical names
+ if ($newsection =~ m/^description$/i) {
+ $newsection = $section_default;
+ } elsif ($newsection =~ m/^context$/i) {
+ $newsection = $section_context;
+ } elsif ($newsection =~ m/^returns?$/i) {
+ $newsection = $section_return;
+ } elsif ($newsection =~ m/^\@return$/) {
+ # special: @return is a section, not a param description
+ $newsection = $section_return;
+ }
+
if (($contents ne "") && ($contents ne "\n")) {
if (!$in_doc_sect && $verbose) {
print STDERR "${file}:$.: warning: contents before sections\n";
@@ -2759,14 +2872,16 @@ sub process_file($) {
$in_doc_sect = 1;
$in_purpose = 0;
$contents = $newcontents;
+ $new_start_line = $.;
+ while ((substr($contents, 0, 1) eq " ") ||
+ substr($contents, 0, 1) eq "\t") {
+ $contents = substr($contents, 1);
+ }
if ($contents ne "") {
- while ((substr($contents, 0, 1) eq " ") ||
- substr($contents, 0, 1) eq "\t") {
- $contents = substr($contents, 1);
- }
$contents .= "\n";
}
$section = $newsection;
+ $leading_space = undef;
} elsif (/$doc_end/) {
if (($contents ne "") && ($contents ne "\n")) {
dump_section($file, $section, xml_escape($contents));
@@ -2780,7 +2895,7 @@ sub process_file($) {
}
$prototype = "";
- $state = 3;
+ $state = STATE_PROTO;
$brcount = 0;
# print STDERR "end of doc comment, looking for prototype\n";
} elsif (/$doc_content/) {
@@ -2791,6 +2906,7 @@ sub process_file($) {
dump_section($file, $section, xml_escape($contents));
$section = $section_default;
$contents = "";
+ $new_start_line = $.;
} else {
$contents .= "\n";
}
@@ -2801,87 +2917,86 @@ sub process_file($) {
$declaration_purpose .= " " . xml_escape($1);
$declaration_purpose =~ s/\s+/ /g;
} else {
- $contents .= $1 . "\n";
+ my $cont = $1;
+ if ($section =~ m/^@/ || $section eq $section_context) {
+ if (!defined $leading_space) {
+ if ($cont =~ m/^(\s+)/) {
+ $leading_space = $1;
+ } else {
+ $leading_space = "";
+ }
+ }
+
+ $cont =~ s/^$leading_space//;
+ }
+ $contents .= $cont . "\n";
}
} else {
# i dont know - bad line? ignore.
print STDERR "${file}:$.: warning: bad line: $_";
++$warnings;
}
- } elsif ($state == 5) { # scanning for split parameters
+ } elsif ($state == STATE_INLINE) { # scanning for inline parameters
# First line (state 1) needs to be a @parameter
- if ($split_doc_state == 1 && /$doc_split_sect/o) {
+ if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) {
$section = $1;
$contents = $2;
+ $new_start_line = $.;
if ($contents ne "") {
while ((substr($contents, 0, 1) eq " ") ||
substr($contents, 0, 1) eq "\t") {
$contents = substr($contents, 1);
}
- $contents .= "\n";
+ $contents .= "\n";
}
- $split_doc_state = 2;
+ $inline_doc_state = STATE_INLINE_TEXT;
# Documentation block end */
- } elsif (/$doc_split_end/) {
+ } elsif (/$doc_inline_end/) {
if (($contents ne "") && ($contents ne "\n")) {
dump_section($file, $section, xml_escape($contents));
$section = $section_default;
$contents = "";
}
- $state = 3;
- $split_doc_state = 0;
+ $state = STATE_PROTO;
+ $inline_doc_state = STATE_INLINE_NA;
# Regular text
} elsif (/$doc_content/) {
- if ($split_doc_state == 2) {
+ if ($inline_doc_state == STATE_INLINE_TEXT) {
$contents .= $1 . "\n";
- } elsif ($split_doc_state == 1) {
- $split_doc_state = 4;
+ # nuke leading blank lines
+ if ($contents =~ /^\s*$/) {
+ $contents = "";
+ }
+ } elsif ($inline_doc_state == STATE_INLINE_NAME) {
+ $inline_doc_state = STATE_INLINE_ERROR;
print STDERR "Warning(${file}:$.): ";
print STDERR "Incorrect use of kernel-doc format: $_";
++$warnings;
}
}
- } elsif ($state == 3) { # scanning for function '{' (end of prototype)
- if (/$doc_split_start/) {
- $state = 5;
- $split_doc_state = 1;
+ } elsif ($state == STATE_PROTO) { # scanning for function '{' (end of prototype)
+ if (/$doc_inline_start/) {
+ $state = STATE_INLINE;
+ $inline_doc_state = STATE_INLINE_NAME;
} elsif ($decl_type eq 'function') {
- process_state3_function($_, $file);
+ process_proto_function($_, $file);
} else {
- process_state3_type($_, $file);
+ process_proto_type($_, $file);
}
- } elsif ($state == 4) {
- # Documentation block
- if (/$doc_block/) {
- dump_doc_section($file, $section, xml_escape($contents));
- $contents = "";
- $function = "";
- %constants = ();
- %parameterdescs = ();
- %parametertypes = ();
- @parameterlist = ();
- %sections = ();
- @sectionlist = ();
- $prototype = "";
- if ( $1 eq "" ) {
- $section = $section_intro;
- } else {
- $section = $1;
- }
- }
- elsif (/$doc_end/)
+ } elsif ($state == STATE_DOCBLOCK) {
+ if (/$doc_end/)
{
dump_doc_section($file, $section, xml_escape($contents));
+ $section = $section_default;
$contents = "";
$function = "";
- %constants = ();
%parameterdescs = ();
%parametertypes = ();
@parameterlist = ();
%sections = ();
@sectionlist = ();
$prototype = "";
- $state = 0;
+ $state = STATE_NORMAL;
}
elsif (/$doc_content/)
{
@@ -2898,7 +3013,7 @@ sub process_file($) {
}
if ($initial_section_counter == $section_counter) {
print STDERR "${file}:1: warning: no structured comments found\n";
- if (($function_only == 1) && ($show_not_found == 1)) {
+ if (($output_selection == OUTPUT_INCLUDE) && ($show_not_found == 1)) {
print STDERR " Was looking for '$_'.\n" for keys %function_table;
}
if ($output_mode eq "xml") {