Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Литература_1 / sys_arch

.pdf
Скачиваний:
44
Добавлен:
02.04.2015
Размер:
3.14 Mб
Скачать

2008, QNX Software Systems GmbH & Co. KG.

Bound multiprocessing (BMP)

On a non-SMP system, there’s no need for a spinlock.

For more information, see the Multicore Processing User’s Guide.

Bound multiprocessing (BMP)

Bound multiprocessing provides the scheduling control of an asymmetric multiprocessing model, while preserving the hardware abstraction and management of symmetric multiprocessing. BMP is similar to SMP, but you can specify which processors a thread can run on. You can use both SMP and BMP on the same system, allowing some threads to migrate from one processor to another, while other threads are restricted to one or more processors.

As with SMP, a single copy of the OS maintains an overall view of all system resources, allowing them to be dynamically allocated and shared among applications. But, during application initialization, a setting determined by the system designer forces all of an application’s threads to execute only on a specified CPU.

Compared to full, floating SMP operation, this approach offers several advantages:

It eliminates the cache thrashing that can reduce performance in an SMP system by allowing applications that share the same data set to run exclusively on the same CPU.

It offers simpler application debugging than SMP since all execution threads within an application run on a single CPU.

It helps legacy applications that use poor techniques for synchronizing shared data to run correctly, again by letting them run on a single CPU.

With BMP, an application locked to one CPU can’t use other CPUs, even if they’re idle. However, Neutrino lets you dynamically change the designated CPU, without having to checkpoint, and then stop and restart the application.

QNX Neutrino supports the concept of hard processor affinity through a runmask. Each bit that’s set in the runmask represents a processor that a thread can run on. By default, a thread’s runmask is set to all ones, allowing it to run on any processor. A value of 0x01 would allow a thread to execute only on the first processor.

By default, a process’s or thread’s children don’t inherit the runmask; there’s a separate inherit mask.

By careful use of these masks, a systems designer can further optimize the runtime performance of a system (e.g. by relegating nonrealtime processes to a specific processor). In general, however, this shouldn’t be necessary, because our realtime scheduler will always preempt a lower-priority thread immediately when a higher-priority thread becomes ready. Processor locking will likely affect only the efficiency of the cache, since threads can be prevented from migrating.

You can specify the runmask for a new thread or process by:

October 16, 2008

Chapter 5 Multicore Processing 103

Choosing between AMP, SMP, and BMP

2008, QNX Software Systems GmbH & Co. KG.

setting the runmask member of the inheritance structure and specifying the

SPAWN_EXPLICIT_CPU flag when you call spawn()

Or:

using the -C or -R option to the on utility when you launch a program. This also sets the process’s inherit mask to the same value.

You can change the runmask for an existing thread or process by:

using the _NTO_TCTL_RUNMASK or _NTO_TCTL_RUNMASK_GET_AND_SET_INHERIT command to the ThreadCtl() kernel call

Or:

using the -C or -R option to the slay utility. If you also use the -i option, slay sets the inherit mask to the same value.

For more information, see the Multicore Processing User’s Guide.

A viable migration strategy

As a midway point between AMP and SMP, BMP offers a viable migration strategy if you wish to move towards full SMP, but you’re concerned that your existing code may operate incorrectly in a truly concurrent execution model.

You can port legacy code to a multicore system and initially bind it to a single CPU to ensure correct operation. By judiciously binding applications (and possibly single threads) to specific CPUs, you can isolate potential concurrency issues down to the application and thread level. Resolving these issues will allow the application to run fully concurrently, thereby maximizing the performance gains provided by the multiple processors.

Choosing between AMP, SMP, and BMP

The choice between AMP, SMP, and BMP depends on the problem you’re trying to solve:

AMP works well with legacy applications, but has limited scalability beyond two CPUs.

SMP offers transparent resource management, but software that hasn’t been properly designed for concurrency might have problems.

BMP offers many of the same benefits as SMP, but guarantees that uniprocessor applications will behave correctly, greatly simplifying the migration of legacy software.

As the following table illustrates, the flexibility to choose from any of these models lets you strike the optimal balance between performance, scalability, and ease of migration.

104

Chapter 5 Multicore Processing

October 16, 2008

2008, QNX Software Systems GmbH & Co. KG.

Choosing between AMP, SMP, and BMP

Feature

SMP

BMP

AMP

Seamless resource

Yes

Yes

sharing

 

 

 

Scalable beyond dual

Yes

Yes

Limited

CPU

 

 

 

Legacy application

In most cases

Yes

Yes

operation

 

 

 

Mixed OS environment

Yes

(e.g. Neutrino and

 

 

 

Linux)

 

 

 

Dedicated processor by

Yes

Yes

function

 

 

 

Intercore messaging

Fast (OS primitives)

Fast (OS primitives)

Slower (application)

Thread synchronization

Yes

Yes

between CPUs

 

 

 

Load balancing

Yes

Yes

System-wide debugging

Yes

Yes

and optimization

 

 

 

October 16, 2008

Chapter 5 Multicore Processing 105

Chapter 6

Process Manager

In this chapter. . .

Introduction 109

 

Process management

109

Memory management

114

Pathname management

119

October 16, 2008

Chapter 6 Process Manager 107

2008, QNX Software Systems GmbH & Co. KG.

Introduction

Introduction

In QNX Neutrino, the microkernel is paired with the Process Manager in a single module (procnto). This module is required for all runtime systems.

The process manager is capable of creating multiple POSIX processes (each of which may contain multiple POSIX threads). Its main areas of responsibility include:

process management — manages process creation, destruction, and process attributes such as user ID (uid) and group ID (gid).

memory management — manages a range of memory-protection capabilities, shared libraries, and interprocess POSIX shared-memory primitives.

pathname management — manages the pathname space into which resource managers may attach.

User processes can access microkernel functions directly via kernel calls and process manager functions by sending messages to procnto. Note that a user process sends a message by invoking the MsgSend*() kernel call.

It’s important to note that threads executing within procnto invoke the microkernel in exactly the same way as threads in other processes. The fact that the process manager code and the microkernel share the same process address space doesn’t imply a “special” or “private” interface. All threads in the system share the same consistent kernel interface and all perform a privilege switch when invoking the microkernel.

Process management

The first responsibility of procnto is to dynamically create new processes. These processes will then depend on procnto’s other responsibilities of memory management and pathname management.

Process management consists of both process creation and destruction as well as the management of process attributes such as process IDs, process groups, user IDs, etc.

Process primitives

The process primitives include:

posix_spawn()

POSIX

spawn()

QNX Neutrino

fork()

POSIX

vfork()

UNIX BSD extension

exec*()

POSIX

October 16, 2008

Chapter 6 Process Manager 109

Process management

2008, QNX Software Systems GmbH & Co. KG.

posix_spawn()

The posix_spawn() function creates a child process by directly specifying an executable to load. To those familiar with UNIX systems, the call is modeled after a fork() followed by an exec*(). However, it operates much more efficiently in that there’s no need to duplicate address spaces as in a fork(), only to destroy and replace it when the exec*() is called.

In a UNIX system, one of the main advantages of using the fork()-then-exec*() method of creating a child process is the flexibility in changing the default environment inherited by the new child process. This is done in the forked child just before the exec*(). For example, the following simple shell command would close and reopen the standard output before exec*()’ing:

ls >file

You can do the same with posix_spawn(); it gives you control over the following classes of environment inheritance, which are often adjusted when creating a new child process:

file descriptors

process user and group IDs

signal mask

ignored signals

adaptive partitioning (scheduler ) attributes

There’s also a companion function, posix_spawnp(), that doesn’t require the absolute path to the program to spawn, but instead searches for the executable using the caller’s

PATH.

Using the posix_spawn() functions is the preferred way to create a new child process.

spawn()

The QNX Neutrino spawn() function is similar to posix_spawn(). The spawn() function gives you control over the following:

file descriptors

process group ID

signal mask

ignored signals

the node to create the process on

scheduling policy

scheduling parameters (priority)

110

Chapter 6 Process Manager

October 16, 2008

2008, QNX Software Systems GmbH & Co. KG.

Process management

maximum stack size

runmask (for SMP systems)

The basic forms of the spawn() function are:

spawn() Spawn with the explicitly specified path.

spawnp() Search the current PATH and invoke spawn() with the first matching executable.

There’s also a set of convenience functions that are built on top of spawn() and spawnp() as follows:

spawnl()

Spawn with the command line provided as inline arguments.

spawnle()

spawnl() with explicitly passed environment variables.

spawnlp()

spawnp() that follows the command search path.

spawnlpe()

spawnlp() with explicitly passed environment variables.

spawnv()

Spawn with the command line pointed to by an array of pointers.

spawnve()

spawnv() with explicitly passed environment variables.

spawnvp()

spawnv() that follows the command search path.

spawnvpe()

spawnvp() with explicitly passed environment variables.

When a process is spawn()’ed, the child process inherits the following attributes of its parent:

process group ID (unless SPAWN_SETGROUP is set in inherit.flags)

session membership

real user ID and real group ID

supplementary group IDs

priority and scheduling policy

current working directory and root directory

file creation mask

signal mask (unless SPAWN_SETSIGMASK is set in inherit.flags)

signal actions specified as SIG_DFL

signal actions specified as SIG_IGN (except the ones modified by inherit.sigdefault when SPAWN_SETSIGDEF is set in inherit.flags)

October 16, 2008

Chapter 6 Process Manager 111

Process management

2008, QNX Software Systems GmbH & Co. KG.

The child process has several differences from the parent process:

Signals set to be caught by the parent process are set to the default action (SIG_DFL).

The child process’s tms_utime, tms_stime, tms_cutime, and tms_cstime are tracked separately from the parent’s.

The number of seconds left until a SIGALRM signal would be generated is set to zero for the child process.

The set of pending signals for the child process is empty.

File locks set by the parent aren’t inherited.

Per-process timers created by the parent aren’t inherited.

Memory locks and mappings set by the parent aren’t inherited.

If the child process is spawned on a remote node, the process group ID and the session membership aren’t set; the child process is put into a new session and a new process group.

The child process can access the parent process’s environment by using the environ global variable (found in <unistd.h>).

For more information, see the spawn() function in the QNX Neutrino Library

Reference.

fork()

The fork() function creates a new child process by sharing the same code as the calling process and duplicating the calling process’s data to give the child process an exact copy. Most process resources are inherited. The following lists some resources that are explicitly not inherited:

process ID

parent process ID

file locks

pending signals and alarms

timers

The fork() function is typically used for one of two reasons:

to create a new instance of the current execution environment

to create a new process running a different program

112

Chapter 6 Process Manager

October 16, 2008

Соседние файлы в папке Литература_1