# 实时Linux内核调度器 | Real-Time Linux Kernel Scheduler

【Linux内核】 专栏收录该内容
383 篇文章 10 订阅

《Real-Time Linux Kernel Scheduler》 HOWTOs by Ankita Garg on August 1, 2009

Design Goal 设计目标

Overview of the -rt Patchset Scheduling Algorithm -rt补丁集调度算法概述

Important -rt Patchset Scheduler Data Structures and Concepts 重要的-rt Patchset Scheduler数据结构和概念

Root Domain

CPU Priority Management - CPU优先级管理

Details of the Push Scheduling Algorithm 推送计划算法的详细信息

Details of the Pull Scheduling Algorithm - PULL调度算法的详细信息

Scheduling Example

Summary

Legal Statement 法律声明

Resources

Index of /pub/linux/kernel/projects/rt/

Real-Time Linux Wiki

Many market sectors, such as financial trading, defense, industry automation and gaming, long have had a need for low latencies and deterministic response time. Traditionally, custom-built hardware and software were used to meet these real-time requirements. However, for some soft real-time requirements, where predictability of response times is advantageous and not mandatory, this is an expensive solution. With the advent of the PREEMPT_RT patchset, referred to as -rt henceforth, led by Ingo Molnar, Linux has made great progress in the world of real-time operating systems for “enterprise real-time” applications. A number of modifications were made to the general-purpose Linux kernel to make Linux a viable choice for real time, such as the scheduler, interrupt handling, locking mechanism and so on.

A real-time system is one that provides guaranteed system response times for events and transactions—that is, every operation is expected to be completed within a certain rigid time period. A system is classified as hard real-time if missed deadlines cause system failure and soft real-time if the system can tolerate some missed time constraints.

# Design Goal 设计目标

The standard Linux kernel provides two real-time scheduling policies, SCHED_FIFO and SCHED_RR. The main real-time policy is SCHED_FIFO. It implements a first-in, first-out scheduling algorithm. When a SCHED_FIFO task starts running, it continues to run until it voluntarily yields the processor, blocks or is preempted by a higher-priority real-time task. It has no timeslices. All other tasks of lower priority will not be scheduled until it relinquishes the CPU. Two equal-priority SCHED_FIFO tasks do not preempt each other. SCHED_RR is similar to SCHED_FIFO, except that such tasks are allotted timeslices based on their priority and run until they exhaust their timeslice. Non-real-time tasks use the SCHED_NORMAL scheduling policy (older kernels had a policy named SCHED_OTHER).

In the standard Linux kernel, real-time priorities range from zero to (MAX_RT_PRIO-1), inclusive. By default, MAX_RT_PRIO is 100. Non-real-time tasks have priorities in the range of MAX_RT_PRIO to (MAX_RT_PRIO + 40). This constitutes the nice values of SCHED_NORMAL tasks. By default, the –20 to 19 nice range maps directly onto the priority range of 100 to 139.

# Overview of the -rt Patchset Scheduling Algorithm -rt补丁集调度算法概述

The real-time scheduler of the -rt patchset adopts an active push-pull strategy developed by Steven Rostedt and Gregory Haskins for balancing tasks across CPUs. The scheduler has to address several scenarios:

1. Where to place a task optimally on wakeup (that is, pre-balance).

2. What to do with a lower-priority task when it wakes up but is on a runqueue running a task of higher priority.

3. What to do with a low-priority task when a higher-priority task on the same runqueue wakes up and preempts it.

4. What to do when a task lowers its priority and thereby causes a previously lower-priority task to have the higher priority.

1. 唤醒时将任务放在何处为最佳（即预平衡）。

2. 在运行较高优先级任务的运行队列上的较低优先级的任务醒来时该怎么办。

3. 当低优先级任务在同一运行队列上被唤醒，高优先级任务也环形并抢占它时，该怎么办。

4. 当任务降低其优先级并因此导致先前较低优先级的任务具有较高优先级时该怎么办。

A push operation is initiated in cases 2 and 3 above. The push algorithm considers all the runqueues within its root domain (discussed later) to find the one that is of a lower priority than the task being pushed.

A pull operation is performed for case 4 above. Whenever a runqueue is about to schedule a task that is lower in priority than the previous one, it checks to see whether it can pull tasks of higher priority from other runqueues.

Real-time tasks are affected only by the push and pull operations. The CFS load-balancing algorithm does not handle real-time tasks at all, as it has been observed that the load balancing pulls real-time tasks away from runqueues to which they were correctly assigned, inducing unnecessary latencies.

# Important -rt Patchset Scheduler Data Structures and Concepts 重要的-rt Patchset Scheduler数据结构和概念

The main per-CPU runqueue data structure struct rq, holds a structure struct rt_rq that encapsulates information about the real-time tasks placed on the per-CPU runqueue, as shown in Listing 1.

Listing 1. struct rt_rq

struct rt_rq {
struct rt_prio_array  active;
...
unsigned long         rt_nr_running;
unsigned long         rt_nr_migratory;
unsigned long         rt_nr_uninterruptible;
int                   highest_prio;
};

Real-time tasks have a priority in the range of 0–99. These tasks are organized on a runqueue in a priority-indexed array active, of type struct rt_prio_array. An rt_prio_array consists of an array of subqueues. There is one subqueue per priority level. Each subqueue contains the runnable real-time tasks at the corresponding priority level. There is also a bitmask corresponding to the array that is used to determine effectively the highest-priority task on the runqueue.


/* Real-Time classes' related field in a runqueue: */
struct rt_rq {
struct rt_prio_array	active;
unsigned int		rt_nr_running;
unsigned int		rr_nr_running;
#if defined CONFIG_SMP || defined CONFIG_RT_GROUP_SCHED
struct {
int		curr; /* highest queued rt task prio */
#ifdef CONFIG_SMP
int		next; /* next highest */
#endif
} highest_prio;
#endif
#ifdef CONFIG_SMP
unsigned long		rt_nr_migratory;
unsigned long		rt_nr_total;

#endif /* CONFIG_SMP */
int			rt_queued;

int			rt_throttled;
u64			rt_time;
u64			rt_runtime;
/* Nests inside the rq lock: */
raw_spinlock_t		rt_runtime_lock;

#ifdef CONFIG_RT_GROUP_SCHED
unsigned long		rt_nr_boosted;

struct rq		*rq;
#endif
};

rt_nr_running and rt_nr_uninterruptible are counts of the number of runnable real-time tasks and the number of tasks in the TASK_UNINTERRUPTIBLE state, respectively.

The highest_prio field indicates the priority of the highest-priority task queued on the runqueue. This may or may not be the priority of the task currently executing on the runqueue (the highest-priority task could have just been enqueued on the runqueue and is pending a schedule). This variable is updated whenever a task is enqueued on a runqueue. The value of the highest_prio is used when scanning every runqueue to find the lowest-priority runqueue for pushing a task. If the highest_prio of the target runqueue is smaller than the task to be pushed, the task is pushed to that runqueue.

maximum_prio字段指示在运行队列中排队的最高优先级任务的优先级。这可能是当前在运行队列上执行的任务的优先级，也可能不是该任务的优先级（最高优先级的任务可能刚被排队在运行队列上，并且正在等待调度）。每当将任务排入运行队列时，都会更新此变量。在扫描每个运行队列以查找用于推送任务的最低优先级运行队列时，将使用highest_prio的值。如果目标运行队列的highest_prio小于要推送的任务，则将任务推送到该运行队列。

Figure 1 shows the values of the above data structures in an example scenario.

Figure 1. Example Runqueues

# Root Domain

As mentioned before, because the real-time scheduler requires several global, or system-wide, resources for making scheduling decisions, scalability bottlenecks appear as the number of CPUs increase (due to increased contention for the locks protecting these resources). For instance, in order to find out if the system is overloaded with real-time tasks—that is, has more runnable real-time tasks than the number of CPUs—it needs to look at the state of all the runqueues. In earlier versions, a global rt_overload variable was used to track the status of all the runqueues on a system. This variable would then be used by the scheduler on every call to the schedule() routine, thus leading to huge contention.

Recently, several enhancements were made to the scheduler to reduce the contention for such variables to improve scalability. The concept of root domains was introduced by Gregory Haskins for this purpose. cpusets provide a mechanism to partition CPUs into a subset that is used by a process or a group of processes. Several cpusets could overlap. A cpuset is called exclusive if no other cpuset contains overlapping CPUs. Each exclusive cpuset defines an isolated domain (called a root domain) of CPUs partitioned from other cpusets or CPUs. Information pertaining to every root domain is stored in struct root_domain, as shown in Listing 2. These root domains are used to narrow the scope of the global variables to per-domain variables. Whenever an exclusive cpuset is created, a new root domain object is created with information from the member CPUs. By default, a single high-level root domain is created with all CPUs as members. With the rescoping of the rt_overload variable, the cache-line bouncing would affect only the members of a particular domain and not the entire system. All real-time scheduling decisions are made only within the scope of a root domain.

Listing 2. struct root_domain

struct root_domain {
atomic_t   refcount;  /* reference count for the domain */
cpumask_t  span;      /* span of member cpus of the domain*/
cpumask_t  online;    /* number of online cpus in the domain*/
atomic_t   rto_count; /* number of overloaded cpus */
....
};

# CPU Priority Management - CPU优先级管理

CPU Priority Management is an infrastructure also introduced by Gregory Haskins to make task migration decisions efficient. This code tracks the priority of every CPU in the system. Every CPU can be in any one of the following states: INVALID, IDLE, NORMAL, RT1, ... RT99.

CPUs in the INVALID state are not eligible for task routing. The system maintains this state with a two-dimensional bitmap: one dimension for the different priority levels and the second for the CPUs in that priority level (priority of a CPU is equivalent to the rq->rt.highest_prio). This is implemented using three arrays, as shown in Listing 3.

Listing 3. struct cpupri

struct cpupri {
struct cpupri_vec  pri_to_cpu[CPUPRI_NR_PRIORITIES];
long               pri_active[CPUPRI_NR_PRI_WORDS];
int                cpu_to_pri[NR_CPUS];
};

The pri_active bitmap tracks those priority levels that contain one or more CPUs. For example, if there is a CPU at priority 49, pri_active[49+2]=1 (real-time task priorities are mapped to 2–102 internally in order to account for priorities INVALID and IDLE), finding the first set bit of this array would yield the lowest priority that any of the CPUs in a given cpuset is in.

pri_active位图跟踪包含一个或多个CPU的优先级。例如，如果有一个CPU的优先级为49，则pri_active [49 + 2] = 1（实时任务优先级在内部映射为2–102，以便考虑优先级INVALID和IDLE），找到该数组将产生给定cpuset中任何CPU所处的最低优先级。

The field cpu_to_pri indicates the priority of a CPU.

The field pri_to_cpu yields information about all the CPUs of a cpuset that are in a particular priority level. This is encapsulated in struct cpupri_vec, as shown in Listing 4.

Like rt_overload, cpupri also is scoped at the root domain level. Every exclusive cpuset that comprises a root domain consists of a cpupri data value.

Listing 4. struct cpupri_vec

struct cpupri_vec {
raw_spinlock_t  lock;
int             count;  /* number of cpus at a priority level */
};

The CPU Priority Management infrastructure is used to find a CPU to which to push a task, as shown in Listing 5. It should be noted that no locks are taken when the search is performed.

CPU优先级管理基础结构用于查找将任务推送到的CPU，如清单5所示。应该注意的是，执行搜索时不会锁定任何锁。

Listing 5. Finding a CPU to Which to Push a Task

int cpupri_find(struct cpupri      *cp,
{
...
for_each_cpupri_active(cp->pri_active, idx) {
struct cpupri_vec *vec  = &cp->pri_to_cpu[idx];

break;

continue;
return 1;
}
return 0;
}

If a priority level is non-empty and lower than the priority of the task being pushed, the lowest_mask is set to the mask corresponding to the priority level selected. This mask is then used by the push algorithm to compute the best CPU to which to push the task, based on affinity, topology and cache characteristics.

# Details of the Push Scheduling Algorithm 推送计划算法的详细信息

As discussed before, in order to ensure SWSRPS, when a low-priority real-time task gets preempted by a higher one or when a task is woken up on a runqueue that already has a higher-priority task running on it, the scheduler needs to search for a suitable target runqueue for the task. This operation of searching a runqueue and transferring one of its tasks to another runqueue is called pushing a task.

The push_rt_task() algorithm looks at the highest-priority non-running runnable real-time task on the runqueue and considers all the runqueues to find a CPU where it can run. It searches for a runqueue that is of lower priority—that is, one where the currently running task can be preempted by the task that is being pushed. As explained previously, the CPU Priority Management infrastructure is used to find a mask of CPUs that have the lowest-priority runqueues. It is important to select only the best CPU from among all the candidates. The algorithm gives the highest priority to the CPU on which the task last executed, as it is likely to be cache-hot in that location. If that is not possible, the sched_domain map is considered to find a CPU that is logically closest to last_cpu. If this too fails, a CPU is selected at random from the mask.

The push operation is performed until a real-time task fails to be migrated or there are no more tasks to be pushed. Because the algorithm always selects the highest non-running task for pushing, the assumption is that, if it cannot migrate it, then most likely the lower real-time tasks cannot be migrated either and the search is aborted. No lock is taken when scanning for the lowest-priority runqueue. When the target runqueue is found, only the lock of that runqueue is taken, after which a check is made to verify whether it is still a candidate to which to push the task (as the target runqueue might have been modified by a parallel scheduling operation on another CPU). If not, the search is repeated for a maximum of three tries, after which it is aborted.

# Scheduling Example

Consider the scenario shown in Figure 2. Task T2 is being preempted by task T3 being woken on runqueue 0. Similarly, task T7 is voluntarily yielding CPU 3 to task T6 on runqueue 3. We first consider the scheduling action on CPU 0 followed by CPU 3. Also, assume all the CPUs are in the same root domain. The pri_active bitmap for this system of CPUs will look like Figure 3. The numbers in the brackets indicate the actual priority that is offset by two (as explained earlier).

Figure 2. Runqueues Showing Currently Running Tasks and the Next Tasks to Be Run Just before the Push Operation

Figure 3. Per-sched Domain cpupri.pri_active Array before the Push Operation

On CPU 0, the post-schedule algorithm would find the runqueue under real-time overload. It then would initiate a push operation. The first set bit of pri_active yields runqueue of CPU 1 as the lowest-priority runqueue suitable for task T2 to be pushed to (assuming all the tasks being considered are not affined to a subset of CPUs). Once T2 is pushed over, the push algorithm then would try to push T1, because after pushing T2, the runqueue still would be under RT overload. The pri_active after the first operation would be as shown in Figure 4. Because the lowest-priority runqueue has a priority greater than the task to be pushed (T1 of priority 85), the push aborts.

Figure 4. Per-sched Domain cpupri.pri_active Array after the Push Operation

Now, consider scheduling at CPU 3, where the current task of priority 92 is voluntarily giving up the CPU. The next task in the queue is T6. The pre-schedule routine would determine that the priority of the runqueue is being lowered, triggering the pull algorithm. Only runqueues 0 and 1 being under real-time overload would be considered by the pull routine. From runqueue 0, the next highest-priority task T1 is of priority greater than the task to be scheduled—T6, and because T1 < T3 and T6 < T3, T1 is pulled over to runqueue 3. The pull does not abort here, as runqueue 1 is still under overload, and there are chances of a higher-priority task being pulled over. The next highest task, T4 on runqueue 1, also can be pulled over, as its priority is higher than the highest priority on runqueue 3. The pull now aborts, as there are no more overloaded runqueues. The final status of all the runqueues is as shown in Figure 5, which is in accordance with scheduling requirements on real-time systems.

Figure 5. Runqueues after the Push and Pull Operations

Although strict priority scheduling has been achieved, runqueue 3 is in an overloaded state due to the pull operation. This scenario is very rare; however, the community is working on a solution.

A number of locking-related decisions have to be made by the scheduler. The state of the runqueues would vary from the above example, depending on when the scheduling operation is performed on the runqueues. The above example has been simplified for this explanation.

# Summary

The most important goal of a real-time kernel scheduler is to ensure SWSRPS. The scheduler in the CONFIG_PREEMPT_RT kernel uses push and pull algorithms to balance and correctly distribute real-time tasks across the system. Both the push and pull operations try to ensure that a real-time task gets an opportunity to run as soon as possible. Also, in order to reduce the performance and scalability impact that might result from increased contention of global variables, the scheduler uses the concept of root domains and CPU priority management. The scope of the global variables is reduced to a subset of CPUs as opposed to the entire system, resulting in significant reduction of cache penalties and performance improvement.

# Legal Statement 法律声明

This work represents the views of the author and does not necessarily represent the view of IBM. Linux is a copyright of Linus Torvalds. Other company, product and service names may be trademarks or service marks of others.

# Resources

Ankita Garg, a computer science graduate from the P.E.S. Institute of Technology, works as a developer at the Linux Technology Centre, IBM India. She currently is working on the Real-Time Linux Kernel Project. You are welcome to send your comments and suggestions to ankita@in.ibm.com.

# Index of /pub/linux/kernel/projects/rt/

../
2.6.22/                                            08-Aug-2013 18:24       -
2.6.23/                                            08-Aug-2013 18:26       -
2.6.24/                                            08-Aug-2013 18:27       -
2.6.25/                                            08-Aug-2013 18:27       -
2.6.26/                                            08-Aug-2013 18:28       -
2.6.29/                                            08-Aug-2013 18:28       -
2.6.31/                                            04-Nov-2014 14:19       -
2.6.33/                                            08-Aug-2013 18:29       -
3.0/                                               19-Nov-2013 22:02       -
3.10/                                              23-Nov-2017 05:44       -
3.12/                                              08-Jun-2017 13:40       -
3.14/                                              13-Feb-2017 22:26       -
3.18/                                              23-May-2019 16:23       -
3.2/                                               23-Nov-2017 05:53       -
3.4/                                               16-Nov-2016 19:26       -
3.6/                                               19-Nov-2013 22:01       -
3.8/                                               04-Nov-2014 13:35       -
4.0/                                               13-Jul-2015 21:06       -
4.1/                                               29-Nov-2017 22:12       -
4.11/                                              17-Oct-2017 13:42       -
4.13/                                              17-Nov-2017 17:03       -
4.14/                                              22-Jan-2021 19:35       -
4.16/                                              03-Aug-2018 07:39       -
4.18/                                              29-Oct-2018 11:51       -
4.19/                                              08-Jan-2021 18:17       -
4.4/                                               05-Feb-2021 18:01       -
4.6/                                               30-Sep-2016 21:37       -
4.8/                                               23-Dec-2016 15:26       -
4.9/                                               04-Feb-2021 01:30       -
5.0/                                               10-Jul-2019 15:17       -
5.10/                                              03-Feb-2021 17:55       -
5.11/                                              29-Jan-2021 18:52       -
5.2/                                               16-Dec-2019 17:11       -
5.4/                                               02-Feb-2021 16:39       -
5.6/                                               20-Aug-2020 14:23       -
5.9/                                               28-Oct-2020 20:05       -

# 是什么使内核/ OS实时？

https://stackoverflow.com/questions/22241264/what-makes-a-kernel-os-real-time

1. 可以仅仅因为它具有实时调度程序而将其称为实时内核吗？换句话说，如果我有一个Linux内核，并且如果将默认调度程序从O(1)CFS更改为real time scheduler，它将变成RTOS吗？
2. 是否需要硬件的任何支持？通常，我已经看到具有RTOS的嵌入式设备（例如VxWorks，QNX），这些设备是否有任何特殊规定/硬件来支持它们？我知道RTOS进程的运行时间是确定的，但随后可以使用longjump / setjump在确定的时间内获取输出。

• 保证外部中断与中断处理程序启动之间的最大延迟的能力。

请注意，最大等待时间不必特别短（例如微秒），您可以拥有一个实时操作系统，以保证绝对最大等待时间为137毫秒。

• 实时调度程序是一种向线程开发人员提供完全可预测的行为（对开发人员而言）的行为-“下一步运行哪个线程”。

通常，这与保证最大响应延迟的问题是分开的（因为中断处理程序不一定像普通线程一样进行调度），但通常有必要实现实时应用程序。实时OS中的调度程序通常实现大量的优先级。并且它们几乎总是实现优先级继承，以避免优先级反转的情况。

• 因为适合通用用途的OS（服务器和/或台式机）需要具有通常与实时延迟保证不一致的特性。

例如，实时调度程序应具有完全可预测的行为。这意味着，除其他事项外，开发人员为各种任务分配的优先级应由OS独自处理。这可能意味着某些低优先级的任务最终会长时间饿死。但是RT OS必须耸耸肩说“开发人员想要的”。请注意，要获得正确的行为，RT系统开发人员必须担心很多事情，例如任务优先级和CPU亲和力。

通用OS正好相反。您希望能够将应用程序和服务（几乎总是由许多不同的供应商编写的东西）扔在上面（而不是像大多数RT系统那样是一个紧密集成的系统），并获得良好的性能。也许不是绝对最佳的性能，而是好的。

请注意，“良好的性能”不仅可以通过中断延迟来衡量。特别是，您希望CPU和其他资源分配通常被描述为“公平”，而用户，管理员甚至应用程序开发人员不必担心线程优先级，CPU关联性和NUMA节点之类的问题。一个工作可能比另一个工作更重要，但是在通用操作系统中，这并不意味着第二个工作根本就不会获得任何资源。

因此，通用操作系统通常会在优先级相同的线程之间执行时间分片，并可能根据其过去的行为来调整线程的优先级（例如，CPU猪的优先级可能会降低； I / O绑定的线程可能会对其优先级降低）。优先级提高了，因此可以使I / O设备保持工作状态； CPU不足的线程的优先级可能会提高，因此可以不时获得一点CPU时间。

• 不可以，RT调度程序是RT操作系统的必要组件，但是您在OS的其他部分也需要可预测的行为。

• 通常，硬件越简单，其行为就越可预测。因此，PCI-E的可预测性不如PCI，而PCI的可预测性却不如ISA等。有一些专门的I / O总线是为（例如）中断延迟等易于预测的目的而设计的，但是许多RT要求可以这些天用商品硬件可以满足。

# Real-Time Linux Wiki

https://rt.wiki.kernel.org/index.php/Main_Page

Documentation

• Actively maintained PREEMPT_RT kernel patces
• No longer actively maintained

Wiki News

2012-10-20: New page: Reporting Bugs

2012-10-20: New Page: Rteval

2010-09-15: New page: Systems based on Real time preempt Linux

2009-03-19: New page: I/Otop utility

2008-10-21: New page: Schedtop utility

2008-09-13: New page: IO CPU Affinity

2008-05-23: New page: Ftrace

2008-05-07: New page: Cpuset Management Utility

2007-10-23: New page: Preemption test

2007-10-18: New page: Fixed Time Quanta Benchmark (FTQ)

Community News

2016-06-23 Real-Time Summit 2016 CFP

2016-05-13: rt-tests version 1.0

2015-09-28: ANNOUNCE 4.1.7-rt8 gmane

2015-09-28: ANNOUNCE rt-tests-0.94

2015-05-20: Announce 4.0.4-rt1

2015-01-27: Stage win for real-time Linux Stage win for real-time Linux (in german)

2013-11-06: The future of realtime Linux The future of realtime Linux, by Jake Edge

2013-07-24: RTLWS15 15th Real Time Linux Workshop, October 28 to October 31 at the Dipartimento Tecnologie Innovative, Scuola Universitaria Professionale della Svizzera Italiana in Lugano-Manno, Switzerland - Call for papers (ASCII) - Abstract Submission

2012-05-15: RTLWS14 14th Real Time Linux Workshop, October 18 to 20, 2012 at the Department of Computer Science, University of North Carolina at Chapel Hill - Call for papers (ASCII) - Abstract Submission

2011-03-13: RTLWS13 13th Real-Time Linux Workshop on October 20 to 22, 2011 in Prague, Czech Republic - Call for Papers in ASCII - Registration - Abstract Submission

2010-07-05: RTECC (July 29, 2010), Real-Time & Embedded Computing Conference in Portland, OR. Darren Hart, rt wiki admin, to give luncheon keynote: Linux, Real-Time, and Fragmentation.

2010-04-08: RTLWS12 Twelfth Real-Time Linux Workshop on October 25 to 27, 2010 in Nairobi, Kenya (LWN Article)

2009-06-17: Cpuset Version 1.5.1 released. Download packages from the build service for many popular distros here.

2009-06-15: RTLWS11 Eleventh Real-Time Linux Workshop on September 28 to 30, 2009 in Dresden, Germany

2009-03-02: OSPERT 2009 (Jul 2-4), Fifth International Workshop on Operating Systems Platforms for Embedded Real-Time Applications

2008-05-29: RTLWS10 Tenth Real-Time Linux Workshop at the University of Guadalajara, Mexico.

2008-04-27: Ubuntu Ships Real-Time Hardy

2007-10-23: Ubuntu Ships Real-Time in Gutsy

Industry News

2007-11-27: Novell Ships Suse Linux Real Time Enterprise

Tips and Techniques

Utilities

Benchmarks and Test Cases

Further Information

• 0
点赞
• 6
评论
• 2
收藏
• 一键三连
• 扫一扫，分享海报

05-03

08-23 2万+
06-20 9828
07-21 491
05-31 2万+
05-29 1541
10-31 1084
09-21 1413
05-07 3239
12-30 262
04-06 498
01-16
06-26 1753
08-18 7282
10-20 2251
08-18 1万+
09-30 4593