Search This Blog

Monday, November 13, 2023

Software bloat

From Wikipedia, the free encyclopedia

Software bloat is a process whereby successive versions of a computer program become perceptibly slower, use more memory, disk space or processing power, or have higher hardware requirements than the previous version, while making only dubious user-perceptible improvements or suffering from feature creep. The term is not applied consistently; it is often used as a pejorative by end users (bloatware) to describe undesired user interface changes even if those changes had little or no effect on the hardware requirements. In long-lived software, perceived bloat can occur from the software servicing a large, diverse marketplace with many differing requirements. Most end users will feel they only need some limited subset of the available functions, and will regard the others as unnecessary bloat, even if end users with different requirements require those functions.

Actual (measurable) bloat can occur due to de-emphasising algorithmic efficiency in favour of other concerns like developer productivity, or possibly through the introduction of new layers of abstraction like a virtual machine or other scripting engine for the purposes of convenience when developer constraints are reduced. The perception of improved developer productivity, in the case of practising development within virtual machine environments, comes from the developers no longer taking resource constraints and usage into consideration during design and development; this allows the product to be completed faster but it results in increases to the end user's hardware requirements to compensate.

The term "bloatware" is also used to describe unwanted pre-installed software or bundled programs.

Types of bloat

Program bloat

In computer programming, code bloat refers to the presence of program code (source code or machine code) that is perceived as unnecessarily long, slow, or otherwise wasteful of resources.

Causes

Software inefficiency

Software developers involved in the industry during the 1970s had severe limitations on disk space and memory. Every byte and clock cycle was taken into account, and much work went into fitting the programs into available resources. Achieving this efficiency was one of the highest values of computer programmers, and the best programs were often called "elegant", a term used by mathematicians to describe a proof which is tidy, parsimonious and powerful.

By the 21st century, the situation had reversed. Resources were perceived as cheap, and rapidity of coding and headline features for marketing seen as priorities. In part, this is because technological advances have since increased processing capacity and storage density by orders of magnitude, while reducing the relative costs by similar orders of magnitude (see Moore's law). Additionally, the spread of computers through all levels of business and home life has produced a software industry many times larger than it was in the 1970s. Programs are now usually churned out by teams, directed by committees in software development studios (also known as software houses or software factories) where each programmer works on only a part of the whole, on one or more subroutines.

Finally, software development tools and approaches often result in changes throughout a program to accommodate each feature, leading to a large-scale inclusion of code which affects the main operation of the software, and is required in order to support functions that themselves may be only rarely used. In particular, the advances in resources available have led to tools which allow easier development of code, again with less priority given to end efficiency.

Another cause of bloat is independently competing standards and products, which can create a demand for integration. There are now more operating systems, browsers, protocols, and storage formats than there were before, causing bloat in programs due to interoperability issues. For example, a program that once could only save in text format is now demanded to save in HTML, XML, XLS, CSV, PDF, DOC, and other formats.

Niklaus Wirth has summed up the situation in Wirth's law, which states that software speed is decreasing more quickly than hardware speed is increasing.

In his 2001 essay Strategy Letter IV: Bloatware and the 80/20 Myth, Joel Spolsky argues that while 80% of the users only use 20% of the features (a variant on the Pareto principle), each one uses different features. Thus, "lite" software editions turn out to be useless for most, as they miss the one or two special features that are present in the "bloated" version. Spolsky sums the article with a quote by Jamie Zawinski referring to the Mozilla Application Suite (which later became SeaMonkey):

"Convenient though it would be if it were true, Mozilla is not big because it's full of useless crap. Mozilla is big because your needs are big. Your needs are big because the Internet is big. There are lots of small, lean web browsers out there that, incidentally, do almost nothing useful. [...] But being a shining jewel of perfection was not a goal when we wrote Mozilla."

Software bloat may also be a symptom of the second-system effect, described by Fred Brooks in The Mythical Man-Month.

Bloatware

The term "bloatware" may be applied to software that has become bloated through inefficiency or accretion of features as outlined above. The term also commonly refers to software preinstalled on a device, usually by the hardware manufacturer, that is mostly unwanted by the purchaser.

The term may also be applied to the accumulation of unwanted and unused software elements that remain after partial and incomplete uninstallation. These elements may include whole programs, libraries, associated configuration information, or other data. Performance may deteriorate overall as a result of such remnants, as the unwanted software or software components can occupy memory, waste processing time, add disk I/O, consume storage and cause delays at system startup and shutdown. In the worst cases, the leftover software may interfere with the correct operation of wanted software. Bloatware can be easily removed if the user has root access on their device, though the rooting process has its own advantages and disadvantages, such as voiding the manufacturer's warranty, and that certain software refuses to run on rooted devices.

Examples

Comparison of Microsoft Windows minimum hardware requirements (for x86 versions)
Windows version Processor Memory Hard disk
Windows 95 25 MHz 4 MB ~50 MB
Windows 98 66 MHz 16 MB ~200 MB
Windows 2000 133 MHz 32 MB 650 MB
Windows XP (2001) 233 MHz 64 MB 1.5 GB
Windows Vista (2007) 800 MHz 512 MB 15 GB
Windows 7 (2009) 1 GHz 1 GB 16 GB
Windows 8 (2012) 1 GHz 1 GB 16 GB
Windows 10 (2015) 1 GHz 1 GB 16 GB
Windows 11 (2021) 1 GHz

64-bit Dual-Core

4 GB 64 GB

Apple's iTunes has been accused of being bloated by efforts to turn it from a simple media player to an e-commerce and advertising platform, with former PC World editor Ed Bott accusing the company of hypocrisy in its advertising attacks on Windows for similar practices. In 2019, Apple announced the impending closure of the program, a move described by a commentator from The Guardian as being "long overdue", stating that the program had "become baroquely bloated, a striking anomaly for a company that prides itself on elegant and functional design."

Microsoft Windows has also been criticized as being bloated – with reference to Windows Vista and discussing the new, greatly slimmed down Windows 7 core components, Microsoft engineer Eric Traut commented that "This is the core of Windows 7. This is a collection of components that we've taken out. A lot of people think of Windows as this really large, bloated operating system, and that may be a fair characterization, I have to admit. It is large. It contains a lot of stuff in it. But at its core, the kernel and the components that make up the very core of the operating system actually is pretty streamlined." Ed Bott also expressed skepticism, noting that nearly every operating system that Microsoft has ever sold has been criticized as 'bloated' on first release, even those now regarded as the exact opposite, such as MS-DOS. Quoting Paul Thurrott, Bott agreed that the bloat stems from numerous enterprise-level features included in the operating system that were largely irrelevant to the average home user.

CD- and DVD-burning applications such as Nero Burning ROM have become criticized for being bloated. Superfluous features not specifically tailored to the end user are sometimes installed by default through express setups.

A number of technology blogs have also covered the issue of increased bloatware on cell phones. However, they refer to a different issue, specifically that of wireless carriers loading phones with software that, in many cases, cannot be easily, if at all, deleted. This has been most frequently cited with respect to Android devices, although this phenomenon exists on phones running many other operating systems.

Some of the most popular current messaging apps, which were previously only focused on instant messaging, have been criticized for being bloated due to feature creep. WeChat added additional features such as games, subscription services, WeChat Pay e-wallet, a news aggregator, e-commerce hub, e-government feature, cinema booking system, restaurant finder and ridesharing company, which has increased the size of the app from 2 MB in 2011 to 58 MB in 2018. Facebook Messenger, which has been separated from the Facebook app, is similarly criticized for adding additional features such as games, bots and features which copied from Snapchat such as Messenger Day (Stories), face filters, a camera with the ability to edit photos, doodle draw and added emojis and stickers. In January 2018, the head of Facebook Messaging, David A. Marcus, admitted that the app itself is extremely bloated and promised to redesign the whole app to remove unnecessary features and streamline it. The redesigned and streamlined Facebook Messenger app was announced in October 2018, in which its features are reduced to messaging, stories, discover tab and camera.

Alternatives

Some applications, such as GIMP, and software with additional functionality from plug-ins, use extensions or add-ons which are downloaded separately from the main application. These can be created by either the software developer or by third-party developers. Plug-ins, extensions, and add-ons add extra functionality which might have otherwise been packaged in the main program.

Allowing these plug-ins, extensions, and/or add-ons reduces the space used on any one machine, because even though the application, the "plug-in interface", and all the plug-ins combined are larger than the same functionality compiled into one monolithic application, it allows each user to install only the particular add-on features they require, rather than forcing every user to install a much larger monolithic application that includes all of the available features. This results in a "stripped-down" or "out-of-the-box" application that is delivered in a compact package yet is ready for users to add any missing functionality.

Open source software may use a similar technique using preprocessor directives to include features at compile time selectively. This is easier to implement and more secure than a plugin system, but has the disadvantage that a user who wants a specific set of features must compile the program from source.

Sometimes software becomes bloated because of "creeping featurism" (Zawinski's law of software envelopment). One way to reduce that kind of bloat is described by the Unix philosophy of "writing programs that do one thing and do it well," and breaking what would be a single, complicated piece of software into numerous simpler components which can be chained together using pipes, shell scripts, or other forms of interapplication communication.

Event-driven architecture

From Wikipedia, the free encyclopedia
https://en.wikipedia.org/wiki/Event-driven_architecture

Event-driven architecture (EDA) is a software architecture paradigm concerning the production and detection of events.

Overview

An event can be defined as "a significant change in state". For example, when a consumer purchases a car, the car's state changes from "for sale" to "sold". A car dealer's system architecture may treat this state change as an event whose occurrence can be made known to other applications within the architecture. From a formal perspective, what is produced, published, propagated, detected or consumed is a (typically asynchronous) message called the event notification, and not the event itself, which is the state change that triggered the message emission. Events do not travel, they just occur. However, the term event is often used metonymically to denote the notification message itself, which may lead to some confusion. This is due to Event-driven architectures often being designed atop message-driven architectures, where such communication pattern requires one of the inputs to be text-only, the message, to differentiate how each communication should be handled.

This architectural pattern may be applied by the design and implementation of applications and systems that transmit events among loosely coupled software components and services. An event-driven system typically consists of event emitters (or agents), event consumers (or sinks), and event channels. Emitters have the responsibility to detect, gather, and transfer events. An Event Emitter does not know the consumers of the event, it does not even know if a consumer exists, and in case it exists, it does not know how the event is used or further processed. Sinks have the responsibility of applying a reaction as soon as an event is presented. The reaction might or might not be completely provided by the sink itself. For instance, the sink might just have the responsibility to filter, transform and forward the event to another component or it might provide a self-contained reaction to such an event. Event channels are conduits in which events are transmitted from event emitters to event consumers. The knowledge of the correct distribution of events is exclusively present within the event channel.[citation needed] The physical implementation of event channels can be based on traditional components such as message-oriented middleware or point-to-point communication which might require a more appropriate transactional executive framework.

Building systems around an event-driven architecture simplifies horizontal scalability in distributed computing models and makes them more resilient to failure. This is because application state can be copied across multiple parallel snapshots for high-availability. New events can be initiated anywhere, but more importantly propagate across the network of data stores updating each as they arrive. Adding extra nodes becomes trivial as well: you can simply take a copy of the application state, feed it a stream of events and run with it.

Event-driven architecture can complement service-oriented architecture (SOA) because services can be activated by triggers fired on incoming events. This paradigm is particularly useful whenever the sink does not provide any self-contained executive.

SOA 2.0 evolves the implications SOA and EDA architectures provide to a richer, more robust level by leveraging previously unknown causal relationships to form a new event pattern. This new business intelligence pattern triggers further autonomous human or automated processing that adds exponential value to the enterprise by injecting value-added information into the recognized pattern which could not have been achieved previously.

Event structure

An event can be made of two parts, the event header and the event body. The event header might include information such as event name, time stamp for the event, and type of event. The event body provides the details of the state change detected. An event body should not be confused with the pattern or the logic that may be applied in reaction to the occurrence of the event itself.

Event flow layers

An event driven architecture may be built on four logical layers, starting with the sensing of an event (i.e., a significant temporal state or fact), proceeding to the creation of its technical representation in the form of an event structure and ending with a non-empty set of reactions to that event.

Event Producer

The first logical layer is the event producer, which senses a fact and represents that fact as an event message. As an example, an event producer could be an email client, an E-commerce system, a monitoring agent or some type of physical sensor.

Converting the data collected from such a diverse set of data sources to a single standardized form of data for evaluation is a significant task in the design and implementation of this first logical layer. However, considering that an event is a strongly declarative frame, any informational operations can be easily applied, thus eliminating the need for a high level of standardization.

Event channel

This is the second logical layer. An event channel is a mechanism of propagating the information collected from an event generator to the event engine or sink. This could be a TCP/IP connection, or any type of an input file (flat, XML format, e-mail, etc.). Several event channels can be opened at the same time. Usually, because the event processing engine has to process them in near real time, the event channels will be read asynchronously. The events are stored in a queue, waiting to be processed later by the event processing engine.

Event processing engine

The event processing engine is the logical layer responsible for identifying an event, and then selecting and executing the appropriate reaction. It can also trigger a number of assertions. For example, if the event that comes into the event processing engine is a product ID low in stock, this may trigger reactions such as “Order product ID” and “Notify personnel”.

Downstream event-driven activity

This is the logical layer where the consequences of the event are shown. This can be done in many different ways and forms; e.g., an email is sent to someone and an application may display some kind of warning on the screen. Depending on the level of automation provided by the sink (event processing engine) the downstream activity might not be required.

Event processing styles

There are three general styles of event processing: simple, stream, and complex. The three styles are often used together in a mature event-driven architecture.

Simple event processing

Simple event processing concerns events that are directly related to specific, measurable changes of condition. In simple event processing, a notable event happens which initiates downstream action(s). Simple event processing is commonly used to drive the real-time flow of work, thereby reducing lag time and cost.

For example, simple events can be created by a sensor detecting changes in tire pressures or ambient temperature. The car's tire incorrect pressure will generate a simple event from the sensor that will trigger a yellow light advising the driver about the state of a tire.

Event stream processing

In event stream processing (ESP), both ordinary and notable events happen. Ordinary events (orders, RFID transmissions) are screened for notability and streamed to information subscribers. Event stream processing is commonly used to drive the real-time flow of information in and around the enterprise, which enables in-time decision making.

Complex event processing

Complex event processing (CEP) allows patterns of simple and ordinary events to be considered to infer that a complex event has occurred. Complex event processing evaluates a confluence of events and then takes action. The events (notable or ordinary) may cross event types and occur over a long period of time. The event correlation may be causal, temporal, or spatial. CEP requires the employment of sophisticated event interpreters, event pattern definition and matching, and correlation techniques. CEP is commonly used to detect and respond to business anomalies, threats, and opportunities.

Online event processing

Online event processing (OLEP) uses asynchronous distributed event logs to process complex events and manage persistent data. OLEP allows reliably composing related events of a complex scenario across heterogeneous systems. It thereby enables very flexible distribution patterns with high scalability and offers strong consistency. However, it cannot guarantee upper bounds on processing time.

Extreme loose coupling and well distributed

An event-driven architecture is extremely loosely coupled and well distributed. The great distribution of this architecture exists because an event can be almost anything and exist almost anywhere. The architecture is extremely loosely coupled because the event itself doesn't know about the consequences of its cause. e.g. If we have an alarm system that records information when the front door opens, the door itself doesn't know that the alarm system will add information when the door opens, just that the door has been opened.

Semantic Coupling and further research

Event-driven architectures have loose coupling within space, time and synchronization, providing a scalable infrastructure for information exchange and distributed workflows. However, event-architectures are tightly coupled, via event subscriptions and patterns, to the semantics of the underlying event schema and values. The high degree of semantic heterogeneity of events in large and open deployments such as smart cities and the sensor web makes it difficult to develop and maintain event-based systems. In order to address semantic coupling within event-based systems the use of approximate semantic matching of events is an active area of research.

Implementations and examples

Java Swing

The Java Swing API is based on an event-driven architecture. This works particularly well with the motivation behind Swing to provide user interface related components and functionality. The API uses a nomenclature convention (e.g. "ActionListener" and "ActionEvent") to relate and organize event concerns. A class which needs to be aware of a particular event simply implements the appropriate listener, overrides the inherited methods, and is then added to the object that fires the event. A very simple example could be:

public class FooPanel extends JPanel implements ActionListener {
    public FooPanel() {
        super();

        JButton btn = new JButton("Click Me!");
        btn.addActionListener(this);

        this.add(btn);
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        System.out.println("Button has been clicked!");
    }
}

Alternatively, another implementation choice is to add the listener to the object as an anonymous class and thus use the lambda notation (since Java 1.8). Below is an example.

public class FooPanel extends JPanel {
    public FooPanel() {
        super();

        JButton btn = new JButton("Click Me!");
        btn.addActionListener(ae -> System.out.println("Button has been clicked!"));
        this.add(btn);
    }
}

JavaScript

(() => {
  'use strict';

  class EventEmitter {
    constructor() {
      this.events = new Map();
    }

    on(event, listener) {
      if (typeof listener !== 'function') {
        throw new TypeError('The listener must be a function');
      }
      let listeners = this.events.get(event);
      if (!listeners) {
        listeners = new Set();
        this.events.set(event, listeners); 
      }
      listeners.add(listener);
      return this;
    }

    off(event, listener) {
      if (!arguments.length) {
        this.events.clear();
      } else if (arguments.length === 1) {
        this.events.delete(event);
      } else {
        const listeners = this.events.get(event);
        if (listeners) {
          listeners.delete(listener);
        }
      }
      return this;
    }

    emit(event, ...args) {
      const listeners = this.events.get(event);
      if (listeners) {
        for (let listener of listeners) {
          listener.apply(this, args);
        }
      }
      return this;
    }
  }

  this.EventEmitter = EventEmitter;
})();

Usage:

const events = new EventEmitter();
events.on('foo', () => { console.log('foo'); });
events.emit('foo'); // Prints "foo"
events.off('foo');
events.emit('foo'); // Nothing will happen

Object Pascal

Events are one of the fundamental elements of the Object Pascal language. The uni-cast model (one-to-one) is used here, i.e. the sender sends information to only one recipient. This limitation has the advantage that it does not need a special event listener. The event itself is a pointer to a method in another object. If the pointer is not empty, when an event occurs, the event handler is called. Events are commonly used in classes that support GUI. This is not the only area of application for events, however. The following code is an example of using events:

unit MyCustomClass;  

interface

uses
  Classes;
  
type
  {definition of your own event}
  TAccidentEvent = procedure(Sender: TObject; const AValue: Integer) of object;

  TMyCustomObject = class(TObject)
  private
    FData: Integer;              // an example of a simple field in a class
    FOnAccident: TAccidentEvent; // event - reference to a method in some object
    FOnChange: TNotifyEvent;     // event - reference to a method in some object 
    procedure SetData(Value: Integer); // a method that sets the value of a field in the class 
  protected
    procedure DoAccident(const AValue: Integer); virtual; // a method that generates an event based on your own definition 
    procedure DoChange; // a method that generates an event based on a definition from the VCL library 
  public
    constructor Create; virtual;   // class constructor 
    destructor Destroy; override;  // class destructor
  published
    property Data: TAccidentEvent read FData write SetData; // declaration of a property in a class
    property OnAccident: TAccidentEvent read FOnAccident write FOnAccident; // exposing the event outside the class
    property OnChange: TNotifyEvent read FOnChange write FOnChange;         // exposing the event outside the class
    procedure MultiplyBy(const AValue: Integer);  // a method that uses its own definition of the event
  end;
  
implementation

constructor TMyCustomObject.Create;
begin
  FData := 0;
end;

destructor TMyCustomObject.Destroy;
begin
  FData := 0;
  inherited Destroy;
end;

procedure TMyCustomObject.DoAccident(const AValue: Integer);
begin
  if Assigned(FOnAccident)
   then FOnAccident(Self, AValue);
end;

procedure TMyCustomObject.DoChange;
begin
  if Assigned(FOnChange)
   then FOnChange(Self);
end;

procedure TMyCustomObject.MultiplyBy(const AValue: Integer);
begin
  FData := FData * AValue;
  if FData > 1000000
   then DoAccident(FData);
end;

procedure TMyCustomObject.SetData(Value: Integer);
begin
  if FData <> Value
   then
    begin
     FData := Value;
     DoChange;
    end;
end.

The created class can be used as follows:

...
procedure TMyForm.ShowCustomInfo(Sender: TObject);
begin
  if Sender is TMyCustomObject
   then ShowMessage('Data has changed.');
end;

procedure TMyForm.PerformAcident(Sender: TObject; const AValue: Integer);
begin
  if Sender is TMyCustomObject
   then ShowMessage('The data has exceeded 1000000! New value is: ' + AValue.ToString);
end;
...
{declaring a variable that is an object of the specified class}
var
  LMyObject: TMyCustomObject; 
...
{creation of the object}
LMyObject := TMyCustomObject.Create;
...
{assigning a methods to an events}
LMyObject.OnChange := MyForm.ShowCustomInfo;
LMyObject.OnAccident := MyForm.PerformAcident;
...
{removing an object when it is no longer needed}
LMyObject.Free; 
...

Signal (IPC)

From Wikipedia, the free encyclopedia

Signals are standardized messages sent to a running program to trigger specific behavior, such as quitting or error handling. They are a limited form of inter-process communication (IPC), typically used in Unix, Unix-like, and other POSIX-compliant operating systems.

A signal is an asynchronous notification sent to a process or to a specific thread within the same process to notify it of an event. Common uses of signals are to interrupt, suspend, terminate or kill a process. Signals originated in 1970s Bell Labs Unix and were later specified in the POSIX standard.

When a signal is sent, the operating system interrupts the target process' normal flow of execution to deliver the signal. Execution can be interrupted during any non-atomic instruction. If the process has previously registered a signal handler, that routine is executed. Otherwise, the default signal handler is executed.

Embedded programs may find signals useful for inter-process communications, as signals are notable for their Algorithmic efficiency.

Signals are similar to interrupts, the difference being that interrupts are mediated by the CPU and handled by the kernel while signals are mediated by the kernel (possibly via system calls) and handled by individual processes. The kernel may pass an interrupt as a signal to the process that caused it (typical examples are SIGSEGV, SIGBUS, SIGILL and SIGFPE).

History

Sending signals

The kill(2) system call sends a specified signal to a specified process, if permissions allow. Similarly, the kill(1) command allows a user to send signals to processes. The raise(3) library function sends the specified signal to the current process.

Exceptions such as division by zero, segmentation violation (SIGSEGV), and floating point exception (SIGFPE) will cause a core dump and terminate the program.

The kernel can generate signals to notify processes of events. For example, SIGPIPE will be generated when a process writes to a pipe which has been closed by the reader; by default, this causes the process to terminate, which is convenient when constructing shell pipelines.

Typing certain key combinations at the controlling terminal of a running process causes the system to send it certain signals:

  • Ctrl-C (in older Unixes, DEL) sends an INT signal ("interrupt", SIGINT); by default, this causes the process to terminate.
  • Ctrl-Z sends a TSTP signal ("terminal stop", SIGTSTP); by default, this causes the process to suspend execution.
  • Ctrl-\ sends a QUIT signal (SIGQUIT); by default, this causes the process to terminate and dump core.
  • Ctrl-T (not supported on all UNIXes) sends an INFO signal (SIGINFO); by default, and if supported by the command, this causes the operating system to show information about the running command.

These default key combinations with modern operating systems can be changed with the stty command.

Handling signals

Signal handlers can be installed with the signal(2) or sigaction(2) system call. If a signal handler is not installed for a particular signal, the default handler is used. Otherwise the signal is intercepted and the signal handler is invoked. The process can also specify two default behaviors, without creating a handler: ignore the signal (SIG_IGN) and use the default signal handler (SIG_DFL). There are two signals which cannot be intercepted and handled: SIGKILL and SIGSTOP.

Risks

Signal handling is vulnerable to race conditions. As signals are asynchronous, another signal (even of the same type) can be delivered to the process during execution of the signal handling routine.

The sigprocmask(2) call can be used to block and unblock delivery of signals. Blocked signals are not delivered to the process until unblocked. Signals that cannot be ignored (SIGKILL and SIGSTOP) cannot be blocked.

Signals can cause the interruption of a system call in progress, leaving it to the application to manage a non-transparent restart.

Signal handlers should be written in a way that does not result in any unwanted side-effects, e.g. errno alteration, signal mask alteration, signal disposition change, and other global process attribute changes. Use of non-reentrant functions, e.g., malloc or printf, inside signal handlers is also unsafe. In particular, the POSIX specification and the Linux man page signal (7) require that all system functions directly or indirectly called from a signal function are async-signal safe. The signal-safety(7) man page gives a list of such async-signal safe system functions (practically the system calls), otherwise it is an undefined behavior. It is suggested to simply set some volatile sig_atomic_t variable in a signal handler, and to test it elsewhere.

Signal handlers can instead put the signal into a queue and immediately return. The main thread will then continue "uninterrupted" until signals are taken from the queue, such as in an event loop. "Uninterrupted" here means that operations that block may return prematurely and must be resumed, as mentioned above. Signals should be processed from the queue on the main thread and not by worker pools, as that reintroduces the problem of asynchronicity. However, managing a queue is not possible in an async-signal safe way with only sig_atomic_t, as only single reads and writes to such variables are guaranteed to be atomic, not increments or (fetch-and)-decrements, as would be required for a queue. Thus, effectively, only one signal per handler can be queued safely with sig_atomic_t until it has been processed.

Relationship with hardware exceptions

A process's execution may result in the generation of a hardware exception, for instance, if the process attempts to divide by zero or incurs a page fault.

In Unix-like operating systems, this event automatically changes the processor context to start executing a kernel exception handler. In case of some exceptions, such as a page fault, the kernel has sufficient information to fully handle the event itself and resume the process's execution.

Other exceptions, however, the kernel cannot process intelligently and it must instead defer the exception handling operation to the faulting process. This deferral is achieved via the signal mechanism, wherein the kernel sends to the process a signal corresponding to the current exception. For example, if a process attempted integer divide by zero on an x86 CPU, a divide error exception would be generated and cause the kernel to send the SIGFPE signal to the process.

Similarly, if the process attempted to access a memory address outside of its virtual address space, the kernel would notify the process of this violation via a SIGSEGV (segmentation violation signal). The exact mapping between signal names and exceptions is obviously dependent upon the CPU, since exception types differ between architectures.

POSIX signals

The list below documents the signals specified in the Single Unix Specification. All signals are defined as macro constants in the <signal.h> header file. The name of the macro constant consists of a "SIG" prefix followed by a mnemonic name for the signal.

SIGABRT and SIGIOT
"Signal abort", "signal input/output trap"
The SIGABRT signal is sent to a process to tell it to abort, i.e. to terminate. The signal is usually initiated by the process itself when it calls abort() function of the C Standard Library, but it can be sent to the process from outside like any other signal.
SIGIOT indicates that the CPU has executed an explicit "trap" instruction (without a defined function), or an unimplemented instruction (when emulation is unavailable).
Note: "input/output trap" is a misnomer for any CPU "trap" instruction. The term reflects early usage of such instructions, predominantly to implement I/O functions, but they are not inherently tied to device I/O and may be used for other purposes such as communication between virtual & real hosts.
SIGIOT and SIGABRT are typically the same signal, and receipt of that signal may indicate any of the conditions above.
SIGALRM, SIGVTALRM and SIGPROF
"Signal alarm", "signal virtual timer alarm", "signal profiling timer alarm"
The SIGALRM, SIGVTALRM and SIGPROF signals are sent to a process when the corresponding time limit is reached. The process sets these time limits by calling alarm or setitimer. The time limit for SIGALRM is based on real or clock time; SIGVTALRM is based on CPU time used by the process; and SIGPROF is based on CPU time used by the process and by the system on its behalf (known as a profiling timer). On some systems SIGALRM may be used internally by the implementation of the sleep function.
SIGBUS
"Signal bus"
The SIGBUS signal is sent to a process when it causes a bus error. The conditions that lead to the signal being sent are, for example, incorrect memory access alignment or non-existent physical address.
SIGCHLD
"Signal child"
The SIGCHLD signal is sent to a process when a child process terminates, is stopped, or resumes after being stopped. One common usage of the signal is to instruct the operating system to clean up the resources used by a child process after its termination without an explicit call to the wait system call.
SIGCONT
"Signal continue"
The SIGCONT signal instructs the operating system to continue (restart) a process previously paused by the SIGSTOP or SIGTSTP signal. One important use of this signal is in job control in the Unix shell.
SIGFPE
"Signal floating-point error"
The SIGFPE signal is sent to a process when an exceptional (but not necessarily erroneous) condition has been detected in the floating point or integer arithmetic hardware. This may include division by zero, floating point underflow or overflow, integer overflow, an invalid operation or an inexact computation. Behaviour may differ depending on hardware.
SIGHUP
"Signal hangup"
The SIGHUP signal is sent to a process when its controlling terminal is closed. It was originally designed to notify the process of a serial line drop (a hangup). In modern systems, this signal usually means that the controlling pseudo or virtual terminal has been closed. Many daemons (who have no controlling terminal) interpret receipt of this signal as a request to reload their configuration files and flush/reopen their logfiles instead of exiting. nohup is a command to make a command ignore the signal.
SIGILL
"Signal illegal"
The SIGILL signal is sent to a process when it attempts to execute an illegal, malformed, unknown, or privileged instruction.
SIGINT
"Signal interrupt"
The SIGINT signal is sent to a process by its controlling terminal when a user wishes to interrupt the process. This is typically initiated by pressing Ctrl+C, but on some systems, the "delete" character or "break" key can be used.
SIGKILL
"Signal kill"
The SIGKILL signal is sent to a process to cause it to terminate immediately (kill). In contrast to SIGTERM and SIGINT, this signal cannot be caught or ignored, and the receiving process cannot perform any clean-up upon receiving this signal. The following exceptions apply:
  • Zombie processes cannot be killed since they are already dead and waiting for their parent processes to reap them.
  • Processes that are in the blocked state will not die until they wake up again.
  • The init process is special: It does not get signals that it does not want to handle, and thus it can ignore SIGKILL. An exception from this rule is while init is ptraced on Linux.
  • An uninterruptibly sleeping process may not terminate (and free its resources) even when sent SIGKILL. This is one of the few cases in which a UNIX system may have to be rebooted to solve a temporary software problem.
SIGKILL is used as a last resort when terminating processes in most system shutdown procedures if it does not voluntarily exit in response to SIGTERM. To speed the computer shutdown procedure, Mac OS X 10.6, aka Snow Leopard, will send SIGKILL to applications that have marked themselves "clean" resulting in faster shutdown times with, presumably, no ill effects. The command killall -9 has a similar, while dangerous effect, when executed e.g. in Linux; it does not let programs save unsaved data. It has other options, and with none, uses the safer SIGTERM signal.
SIGPIPE
"Signal pipe"
The SIGPIPE signal is sent to a process when it attempts to write to a pipe without a process connected to the other end.
SIGPOLL
"Signal poll"
The SIGPOLL signal is sent when an event occurred on an explicitly watched file descriptor. Using it effectively leads to making asynchronous I/O requests since the kernel will poll the descriptor in place of the caller. It provides an alternative to active polling.
SIGRTMIN to SIGRTMAX
"Signal real-time minimum", "signal real-time maximum"
The SIGRTMIN to SIGRTMAX signals are intended to be used for user-defined purposes. They are real-time signals.
SIGQUIT
"Signal quit"
The SIGQUIT signal is sent to a process by its controlling terminal when the user requests that the process quit and perform a core dump.
SIGSEGV
"Signal segmentation violation"
The SIGSEGV signal is sent to a process when it makes an invalid virtual memory reference, or segmentation fault, i.e. when it performs a segmentation violation.
SIGSTOP
"Signal stop"
The SIGSTOP signal instructs the operating system to stop a process for later resumption.
SIGSYS
"Signal system call"
The SIGSYS signal is sent to a process when it passes a bad argument to a system call. In practice, this kind of signal is rarely encountered since applications rely on libraries (e.g. libc) to make the call for them. SIGSYS can be received by applications violating the Linux Seccomp security rules configured to restrict them. SIGSYS can also be used to emulate foreign system calls, e.g. emulate Windows system calls on Linux.
SIGTERM
"Signal terminate"
The SIGTERM signal is sent to a process to request its termination. Unlike the SIGKILL signal, it can be caught and interpreted or ignored by the process. This allows the process to perform nice termination releasing resources and saving state if appropriate. SIGINT is nearly identical to SIGTERM.
SIGTSTP
"Signal terminal stop"
The SIGTSTP signal is sent to a process by its controlling terminal to request it to stop (terminal stop). It is commonly initiated by the user pressing Ctrl+Z. Unlike SIGSTOP, the process can register a signal handler for, or ignore, the signal.
SIGTTIN and SIGTTOU
The SIGTTIN and SIGTTOU signals are sent to a process when it attempts to read in or write out respectively from the tty while in the background. Typically, these signals are received only by processes under job control; daemons do not have controlling terminals and, therefore, should never receive these signals.
SIGTRAP
"Signal trap"
The SIGTRAP signal is sent to a process when an exception (or trap) occurs: a condition that a debugger has requested to be informed of – for example, when a particular function is executed, or when a particular variable changes value.
SIGURG
"Signal urgent"
The SIGURG signal is sent to a process when a socket has urgent or out-of-band data available to read.
SIGUSR1 and SIGUSR2
"Signal user 1", "signal user 2""
The SIGUSR1 and SIGUSR2 signals are sent to a process to indicate user-defined conditions.
SIGXCPU
"Signal exceeded CPU"
The SIGXCPU signal is sent to a process when it has used up the CPU for a duration that exceeds a certain predetermined user-settable value. The arrival of a SIGXCPU signal provides the receiving process a chance to quickly save any intermediate results and to exit gracefully, before it is terminated by the operating system using the SIGKILL signal.
SIGXFSZ
"Signal excess file size"
The SIGXFSZ signal is sent to a process when it grows a file that exceeds the maximum allowed size.
SIGWINCH
"Signal window change"
The SIGWINCH signal is sent to a process when its controlling terminal changes its size (a window change).

Default action

A process can define how to handle incoming POSIX signals. If a process does not define a behaviour for a signal, then the default handler for that signal is being used. The table below lists some default actions for POSIX-compliant UNIX systems, such as FreeBSD, OpenBSD and Linux.

Signal Portable
number
Default action Description
SIGABRT 6 Terminate (core dump) Process abort signal
SIGALRM 14 Terminate Alarm clock
SIGBUS Terminate (core dump) Access to an undefined portion of a memory object
SIGCHLD Ignore Child process terminated, stopped, or continued
SIGCONT Continue Continue executing, if stopped
SIGFPE 8 Terminate (core dump) Erroneous arithmetic operation
SIGHUP 1 Terminate Hangup
SIGILL 4 Terminate (core dump) Illegal instruction
SIGINT 2 Terminate Terminal interrupt signal
SIGKILL 9 Terminate Kill (cannot be caught or ignored)
SIGPIPE 13 Terminate Write on a pipe with no one to read it
SIGPOLL Terminate Pollable event
SIGPROF Terminate Profiling timer expired
SIGQUIT 3 Terminate (core dump) Terminal quit signal
SIGSEGV 11 Terminate (core dump) Invalid memory reference
SIGSTOP Stop Stop executing (cannot be caught or ignored)
SIGSYS Terminate (core dump) Bad system call
SIGTERM 15 Terminate Termination signal
SIGTRAP 5 Terminate (core dump) Trace/breakpoint trap
SIGTSTP Stop Terminal stop signal
SIGTTIN Stop Background process attempting read
SIGTTOU Stop Background process attempting write
SIGUSR1 Terminate User-defined signal 1
SIGUSR2 Terminate User-defined signal 2
SIGURG Ignore Out-of-band data is available at a socket
SIGVTALRM Terminate Virtual timer expired
SIGXCPU Terminate (core dump) CPU time limit exceeded
SIGXFSZ Terminate (core dump) File size limit exceeded
SIGWINCH Ignore Terminal window size changed
Portable number:
For most signals the corresponding signal number is implementation-defined. This column lists the numbers specified in the POSIX standard.
Actions explained:
Terminate – Abnormal termination of the process. The process is terminated with all the consequences of _exit() except that the status made available to wait() and waitpid() indicates abnormal termination by the specified signal.
Terminate (core dump) – Abnormal termination of the process. Additionally, implementation-defined abnormal termination actions, such as creation of a core file, may occur.
Ignore – Ignore the signal.
Stop – Stop (or suspend) the process.
Continue – Continue the process, if it is stopped; otherwise, ignore the signal.

Miscellaneous signals

The following signals are not specified in the POSIX specification. They are, however, sometimes used on various systems.

SIGEMT
The SIGEMT signal is sent to a process when an emulator trap occurs.
SIGINFO
The SIGINFO signal is sent to a process when a status (info) request is received from the controlling terminal.
SIGPWR
The SIGPWR signal is sent to a process when the system experiences a power failure.
SIGLOST
The SIGLOST signal is sent to a process when a file lock is lost.
SIGSTKFLT
The SIGSTKFLT signal is sent to a process when the coprocessor experiences a stack fault (i.e. popping when the stack is empty or pushing when it is full). It is defined by, but not used on Linux, where a x87 coprocessor stack fault will generate SIGFPE instead.
SIGUNUSED
The SIGUNUSED signal is sent to a process when a system call with an unused system call number is made. It is synonymous with SIGSYS on most architectures.
SIGCLD
The SIGCLD signal is synonymous with SIGCHLD.

Romance (love)

From Wikipedia, the free encyclopedia https://en.wikipedia.org/w...