logo资料库

uCOSII.pdf

第1页 / 共305页
第2页 / 共305页
第3页 / 共305页
第4页 / 共305页
第5页 / 共305页
第6页 / 共305页
第7页 / 共305页
第8页 / 共305页
资料共305页,剩余部分请下载后查看
Preface
Introduction
Chapter 1. Sample Code
1.00 Installing μC/OS-II
1.01 INCLUDES.H
1.02 Compiler Independent Data Types
1.03 Global Variables
1.04 OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL()
1.05 PC Based Services
1.05.01 PC Based Services, Character Based Display
1.05.02 PC Based Services, Elapsed Time Measurement
1.05.03 PC Based Services, Miscellaneous
1.06 μC/OS-II Examples
1.07 Example #1
1.08 Example #2
1.09 Example #3
Chapter 2 Real-Time Systems Concepts
2.00 Foreground/Background Systems
2.01 Critical Section of Code
2.02 Resource
2.03 Shared Resource
2.04 Multitasking
2.05 Task
2.06 Context Switch (or Task Switch)
2.07 Kernel
2.08 Scheduler
2.09 Non-Preemptive Kernel
2.10 Preemptive Kernel
2.11 Reentrancy
2.12 Round Robin Scheduling
2.13 Task Priority
2.14 Static Priorities
2.15 Dynamic Priorities
2.16 Priority Inversions
2.17 Assigning Task Priorities
2.19 Mutual Exclusion
2.20 Deadlock (or Deadly Embrace)
2.21 Synchronization
2.22 Event Flags
2.23 Intertask Communication
2.24 Message Mailboxes
2.25 Message Queues
2.26 Interrupts
2.27 Interrupt Latency
2.28 Interrupt Response
2.29 Interrupt Recovery
2.30 Interrupt Latency, Response, and Recovery
2.31 ISR Processing Time
2.32 Non-Maskable Interrupts (NMIs)
2.33 Clock Tick
2.34 Memory Requirements
2.35 Advantages and Disadvantages of Real-Time Kernels
2.36 Real-Time Systems Summary
Chapter 3 Kernel Structure
3.00 Critical Sections
3.01 Tasks
3.02 Task States
3.03 Task Control Blocks (OS_TCBs)
3.04 Ready List
3.05 Task Scheduling
3.06 Locking and Unlocking the Scheduler
3.07 Idle Task
3.08 Statistics Task
3.09 Interrupts under μC/OS-II
3.10 Clock Tick
3.11 μC/OS-II Initialization
3.12 Starting μC/OS-II
3.13 Obtaining μC/OS-II’s version
3.14 OSEvent???() functions
Chapter 4 Task Management
4.00 Creating a Task, OSTaskCreate()
4.01 Creating a Task, OSTaskCreateExt()
4.02 Task Stacks
4.03 Stack Checking, OSTaskStkChk()
4.04 Deleting a Task, OSTaskDel()
4.05 Requesting to delete a task, OSTaskDelReq()
4.06 Changing a Task’s Priority, OSTaskChangePrio()
4.07 Suspending a Task, OSTaskSuspend()
4.08 Resuming a Task, OSTaskResume()
4.09 Getting Information about a Task, OSTaskQuery()
Chapter 5 Time Management
5.00 Delaying a task, OSTimeDly()
5.01 Delaying a task, OSTimeDlyHMSM()
5.02 Resuming a delayed task, OSTimeDlyResume()
5.03 System time, OSTimeGet() and OSTimeSet()
Chapter 6 Intertask Communication & Synchronization
6.00 Event Control Blocks
6.01 Initializing an ECB, OSEventWaitListInit()
6.02 Making a task ready, OSEventTaskRdy()
6.03 Making a task wait for an event, OSEventTaskWait()
6.04 Making a task ready because of a timeout, OSEventTO()
6.05 Semaphores
6.06 Message Mailboxes
6.07 Message Queues
Chapter 7 Memory Management
7.00 Memory Control Blocks
7.01 Creating a partition, OSMemCreate()
7.02 Obtaining a memory block, OSMemGet()
7.03 Returning a memory block, OSMemPut()
7.04 Obtaining status about memory partition, OSMemQuery()
7.05 Using memory partitions
7.06 Waiting for memory blocks from a partition
Chapter 8 Porting μC/OS-II
8.00 Development Tools
8.01 Directories and Files
8.02 INCLUDES.H
8.03 OS_CPU.H
8.04 OS_CPU_A.ASM
8.05 OS_CPU_C.C
Chapter 9 80x86, Large Model Port
9.00 Development Tools
9.01 Directories and Files
9.02 INCLUDES.H
9.03 OS_CPU.H
9.04 OS_CPU_A.ASM
9.05 OS_CPU_C.C
9.06 Memory requirements
9.07 Execution times
Chapter 10 Upgrading from μC/OS to μC/OS-II
10.00 Directories and Files
10.01 INCLUDES.H
10.02 OS_CPU.H
10.02.01 OS_CPU.H, Compiler specific data types
10.02.02 OS_CPU.H, OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL()
10.02.03 OS_CPU.H, OS_STK_GROWTH
10.02.04 OS_CPU.H, OS_TASK_SW()
10.02.05 OS_CPU.H, OS_FAR
10.03 OS_CPU_A.ASM
10.03.01 OS_CPU_A.ASM, OSStartHighRdy()
10.03.02 OS_CPU_A.ASM, OSCtxSw()
10.03.03 OS_CPU_A.ASM, OSIntCtxSw()
10.03.04 OS_CPU_A.ASM, OSTickISR()
10.04 OS_CPU_C.C
10.04.01 OS_CPU_C.C, OSTaskStkInit()
10.04.02 OS_CPU_C.C, OSTaskCreateHook()
10.04.03 OS_CPU_C.C, OSTaskDelHook()
10.04.04 OS_CPU_C.C, OSTaskSwHook()
10.04.05 OS_CPU_C.C, OSTaskStatHook()
10.04.06 OS_CPU_C.C, OSTimeTickHook()
10.05 Summary
Chapter 11 Reference Manual
OSInit()
OSIntEnter()
OSIntExit()
OSMboxAccept()
OSMboxCreate()
OSMboxPend()
OSMboxPost()
OSMboxQuery()
OSMemCreate()
OSMemGet()
OSMemPut()
OSMemQuery()
OSQAccept()
OSQCreate()
OSQFlush()
OSQPend()
OSQPost()
OSQPostFront()
OSQQuery()
OSSchedLock()
OSSchedUnlock()
OSSemAccept()
OSSemCreate()
OSSemPend()
OSSemPost()
OSSemQuery()
OSStart()
OSStatInit()
OSTaskChangePrio()
OSTaskCreate()
OSTaskCreateExt()
OSTaskDel()
OSTaskDelReq()
OSTaskResume()
OSTaskStkChk()
OSTaskSuspend()
OSTaskQuery()
OSTimeDly()
OSTimeDlyHMSM()
OSTimeDlyResume()
OSTimeGet()
OSTimeSet()
OSTimeTick()
OSVersion()
OS_ENTER_CRITICAL() OS_EXIT_CRITICAL()
Chapter 12 Configuration Manual
Appendix E Bibliography
Appendix F Licensing
Preface My first book, “µC/OS, The Real-Time Kernel” is now 6 years old and the publisher has sold well over 15,000 copies around the world. When I was asked to do a second edition, I thought it would be a fairly straightforward task; a few corrections here and there, clarify a few concepts, add a function or two to the kernel, etc. If you have a copy of the first edition, you will notice that “µC/OS-II, The Real-Time Kernel” is in fact a major revision. For some strange reason, I wasn’t satisfied with minor corrections. Also, when my publisher told me that this time, the book would be a ‘hard cover’, I really wanted to give you your moneys worth. In all, I added more than 200 new pages, and re-wrote the majority of the pages I did keep. I added a porting guide to help you port µC/OS-II to the processor of your choice. Also, I added a chapter that will guide you through upgrading a µC/OS port to µC/OS-II. The code for µC/OS-II is basically the same as that of µC/OS except that it contains a number of new and useful features, is much better commented, and should be easier to port to processor architectures. µC/OS-II offers all the features provided in µC/OS as well as the following new features: • • • • • • • A fixed-sized block memory manager, A service to allow a task to suspend its execution for a certain amount of time (specified in hours, minutes, seconds and milliseconds), User definable ‘callout’ functions that are invoked when: a task is created, a task is deleted, a context switch is performed, a clock tick occurs. A new task create function that provides additional features, Stack checking, A function returning the version of µC/OS-II, And more. µC/OS-II Goals Probably the most important goal of µC/OS-II was to make it backward compatible with µC/OS (at least from an application’s standpoint). A µC/OS port might need to be modified to work with µC/OS-II but at least, the application code should require only minor changes (if any). Also, because µC/OS-II is based on the same core as µC/OS, it is just as reliable. I added conditional compilation to allow you to further reduce the amount of RAM (i.e. data space) needed by µC/OS-II. This is especially useful when you have resource limited products. I also added the feature described in the previous section and cleaned up the code. Where the book is concerned, I wanted to clarify some of the concepts described in the first edition and provide additional explanations about how µC/OS-II works. I had numerous requests about doing a chapter on how to port µC/OS and thus, such a chapter has been included in this book for µC/OS-II.
Intended Audience This book is intended for embedded system programmers, consultants and students interested in real-time operating systems. µC/OS-II is a high performance, deterministic real-time kernel and can be embedded in commercial products (see Appendix F, Licensing). Instead of writing your own kernel, you should consider µC/OS-II. You will find, as I did, that writing a kernel is not as easy as it first looks. I’m assuming that you know C and have a minimum knowledge of assembly language. You should also understand microprocessor architectures. What you will need to use µC/OS-II The code supplied with this book assumes that you will be using an IBM -PC/AT or compatible (80386 Minimum) computer running under DOS 4.x or higher. The code was compiled with Borland International’s C++ V3.1. You should have about 5 MBytes of free disk space on you hard drive. I actually compiled and executed the sample code provided in this book in a DOS window under Windows 95. To use µC/OS-II on a different target processor (than a PC), you will need to either port µC/OS-II to that processor yourself or, obtain one from µC/OS-II official WEB site at http://www.uCOS-II.com. You will also need appropriate software development tools such as an ANSI C compiler, an assembler, linker/locator and some way of debugging your application. The µC/OS Story Many years ago, I designed a product based on an Intel 80C188 at Dynalco Controls and I needed a real-time kernel. At my previous employer, I had been using a well known kernel (let’s call it kernel ‘A’) but, found it to be too expensive for the application I was designing. We then found a lower cost kernel ($1000 at the time) and started our design with it. Let’s call this kernel, kernel ‘B’. We spent about two months trying to get a couple of very simple tasks to run. We were calling the vendor almost on a daily basis to get help making this work. The vendor claimed that this kernel was written in C. However, we had to initialize every single object using assembly language code. Although the vendor was very patient, we decided that we had enough of this. Our product was falling behind schedule and we really didn’t want to spend our time debugging this low cost kernel. It turns out that we were one of this vendor’s first customer and the kernel was really not fully tested and debugged! To get back on track, we decided to go back and use kernel ‘A’. The cost was about $5000 for development seat and we had to pay a per usage fee of about $200 for each unit that we shipped! This was a lot of money at the time, but it bought us some peace of mind. We got the kernel up and running in about 2 days! Three months into the project, one of our engineers discovered what looked like a bug in the kernel. We sent the code to the vendor and sure enough, the bug was confirmed as being in the kernel. The vendor provided a 90 day warranty but, that had exp ired so, in order to get support, we had to pay an addition $500 per year for ‘maintenance’. We argued with the salesperson for a few months that they should fix the bug since we were actually doing them a favor. They wouldn’t budge! Finally, we gave in, we bought the maintenance contract and the vendor fixed the bug six months later! Yes, six months later. We were furious but most importantly, late delivering our product. In all, it took close to a year to get our product to work reliably with kernel ‘A’. I must admit, however, that we never had any problems with it since. As this was going on, I naively thought, “Well, it can’t be that difficult to write a kernel. All it needs to do is save and restore processor registers”. That’s when I decided to try it out and write my own (part time at night and on weekends). It took me about a year to get the kernel to be just as good (and in some ways better) than kernel ‘A’. I didn’t want to start a company and sell it because there were already about 50 kernels out there so, why have another one? I then thought of writing a paper for a magazine. I first went to the “C User’s Journal (CUJ)” (the kernel was written in C) which, I had heard, was offering $100 per published page when other magazines were only paying $75 per page. My paper had 70 or so pages so, that would be a nice compensation for all the time I spent working on my kernel.
Unfortunately, the article was rejected! There were two reasons. First, the article was too long and the magazine didn’t want to publish a series. Second, they didn’t want to have ‘another kernel article’. I then decided to turn to Embedded Systems Programming (ESP) magazine because my kernel was designed for embedded systems. I contacted the editor of ESP (Mr. Tyler Sperry) and told him that I had this kernel I wanted to publish in his magazine. I got the same response from Tyler as I did from the C Journal: “Not another kernel article?” I told him that this kernel was different, it was preemptive, it was comparable to many commercial kernels and that he could put the source code on the ESP BBS (Bulletin Board Service). I was calling Tyler two or three times a week (basically begging him) until he finally gave in (he was probably tired of having me call him) and decide to publish the article. My article got edited down from 70 pages to about 30 pages and was published in two consecutive months (May 1992 and June 1992). The article was probably the most popular article in 1992. ESP had over 500 downloads of the code from the BBS in the first month. Tyler may have feared for his life because kernel vendors were upset that he published a kernel in his magazine. I guess that these vendors must have recognized the quality and capabilities of µC/OS (was called µCOS then). The article was really the first that exposed the internals of a real-time kernel so, some of the secrets were out. Just about the time the article came out in ESP, I got a call back from Dr. Bernard Williams at R&D Publications (publisher of CUJ), 6 months after the initial contact with CUJ. He had left a message with my wife and told her that he was interested in the article!??! I called him back and told him something like: “Don’t you think you are a little bit late with this? The article is being published in ESP.” Berney said: “No, No, you don’t understand, because the article is so long, I want to make a book out of it.” Initially, Berney simply wanted to publish what I had (as is) so the book would only have 80 or so pages. I said to him, “If I going to write a book, I want to do it right.” I then spent about 6 months adding contents to what is now know as the first edition. In all, the book had about 250 pages to it. I changed the name of µCOS to µC/OS because ESP readers had been calling it ‘Mucus’ which didn’t sound too healthy! Come to think of it, maybe it was a kernel vendor that first came up with the name. Anyway, µC/OS, The Real-Time Kernel was then born. Sales were somewhat slow to start. Berney and I projected that we would sell about 4000 to 5000 copies in the life of the book but at that rate, we would be lucky if it sold 2000 copies. Berney insisted that these things take time to get known so, he continued advertising in CUJ for about a year. A month or so before the book came out, I went to my first Embedded Systems Conference (ESC) in Santa Clara, CA (September 1992). I then met Tyler Sperry for the first time and I showed him the first draft copy of my book. He very quickly glanced at it and said something like: “Would you like to speak at the next Embedded Systems Conference in Atlanta?” Not knowing any better, I said “Sure, what should I talk about?” He said what about “Using small real-time kernels?” I said “Fine”. On the trip back from California, I was thinking “What did I get myself into? I’ve never spoke in front of a bunch of people before! What if I make a fool of myself? What if what I speak about is common knowledge? Those people pay good money to attend this conference.” For the next six months, I prepared my lecture. At the conference, I had about 70+ attendees. In the first twenty minutes I must have lost one pound of sweat. After my lecture, I had a crowd of about 15 or so people come up to me and say that they were very pleased with the lecture and liked my book. I got re -invited back to the conference but could not attend the one in Santa Clara that year (i.e. 1993). I was able to attend the next conference in Boston (1994) and I have been a regular speaker at ESC ever since. For the past couple of years, I’ve been on the conference Advisory Committee. I now do at least 3 lectures at every conference and each have average attendance of between 200 and 300 people! My lectures are almost always ranked amongst the top 10% of the conference. To date, we sold well over 15,000 copies or µC/OS, The Real-Time Kernel around the world. I received and answered well over 1000 e-mails from the following countries: In 1995, µC/OS, The Real-Time Kernel was translated in Japanese and published in a magazine called Interface in Japan. µC/OS has been ported to the following processors: Analog Devices AD21xx Advanced Risc Machines ARM6, ARM7 Hitachi 64180, H8/3xx, SH series Intel 80x86 (Real and PM), Pentium, Pentium-II, 8051, 8052, MCS-251, 80196, 8096 Mitsubishi M16 and M32
Motorola PowerPC, 68K, CPU32, CPU32+, 68HC11, 68HC16 Philips XA Siemens 80C166 and TriCore Texas instruments TMS320 Zilog Z-80 and Z-180 And more. In 1994, I decided to write my second book: Embedded Systems Building Blocks, Complete and Ready-to-Use Modules in C (ESBB) and contains over 600 pages. For some reason, ESBB has not been as popular as µC/OS although it contains as much valuable information not found anywhere else. I always thought that it would be an ideal book for people just starting in the embedded world. In 1998, I opened the official µC/OS WEB site www.uCOS-II.com. I intend this site to contain ports, application notes, links, answers to frequently asked questions (FAQs), upgrades for both µC/OS and µC/OS-II, and more. All I need is time! Back in 1992, I never imagined that writing an article would have changed my life as it did. I met a lot of very interesting people and made a number of good friends in the process. I still answer every single e-mail that I receive. I believe that if you take the time to write to me then I owe you a response. I hope you enjoy this book. Acknowledgements First and foremost, I would like to thank my wife for her support, encouragement, understanding and especially patience. Manon must have heard the words “Just one more week!” about a dozen times while I was writing this book. I would also like to thank my children James (age 8) and Sabrina (age 4) for putting up with the long hours I had to spend in front of the computer. I hope one day they will understand. I would also like to thank Mr. Niall Murphy for carefully reviewing most of the chapters and providing me with valuable feedback. Special thanks to Mr. Alain Chebrou and Mr. Bob Paddock for passing the code for µC/OS-II through a fine tooth comb. I would like to thank all the fine people at R&D Technical books for their help in making this book a reality, and also for putting up with my insistence on having things done my way. Finally, I would like to thank all the people who have purchased µC/OS, The Real-Time Kernel as well as Embedded Systems Building Blocks and who, by doing so, have encouraged me to pursue this interesting past-time.
Introduction This book describes the design and implementation of m C/OS-II (pronounced "Micro C O S 2") which stands for Micro-Controller Operating System Version 2. µC/OS-II is based on µC/OS, The Real-Time Kernel which was first published in 1992. Thousands of people around the world are using µC/OS in all kinds of applications such as cameras, medical instruments, musical instruments, engine controls, network adapters, highway telephone call boxes, ATM machines, industrial robots, and many more. Nu merous colleges and Universities have also used µC/OS to teach students about real-time systems. µC/OS-II is upward compatible with µC/OS (V1.11) but provides many improvements over µC/OS such as the addition of a fixed-sized memory manager, user definable callouts on task creation, task deletion, task switch and system tick, supports TCB extensions, stack checking and, much more. I also added comments to just about every function and I made µC/OS -II much easier to port to different processors. The source code in µC/OS was found in two source files. Because µC/OS-II contains many new features and functions, I decided to split µC/OS-II in a few source files to make the code easier to maintain. If you currently have an application (i.e. product) that runs with µC/OS, your application should be able to run, virtually unchanged, with µC/OS-II. All of the services (i.e. function calls) provided by µC/OS have been preserved. You may, however, have to change include files and product build files to ‘point’ to the new file names. This book contains ALL the source code for µC/OS-II and a port for the Intel 80x86 processor running in Real-Mode and for the Large Model. The code was developed on a PC running the Microsoft Windows 95 operating system. Examples run in a DOS compatible box under the Windows 95 environment. Development was done using the Borland International C/C++ compiler version 3.1. Although µC/OS-II was developed and tested on a PC, m C/OS-II was actually targeted for embedded systems and can easily be ported to many different processor architectures. µC/OS-II features: Source Code: As I mentioned previously, this book contains ALL the source code for m C/OS-II. I went through a lot of efforts to provide you with a high quality ‘product’. You may not agree with some of the style constructs that I use but you should agree that the code is both clean and very consistent. Many commercial real-time kernels are provided in source form. I challenge you to find any such code that is as neat, consis tent, well commented and organized as µC/OS-II’s. Also, I believe that simply giving you the source code is not enough. You need to know how the code works and how the different pieces fit together. You will find this type of information in this book. The organization of a real-time kernel is not always apparent by staring at many source files and thousands of lines of code. Portable: Most of m C/OS-II is written in highly portable ANSI C, with target microprocessor specific code written in assembly language. Assembly language is kept to a minimum to make µC/OS -II easy to port to other processors. Like µC/OS, µC/OS-II can be ported to a large number of microprocessors as long as the microprocessor provides a stack pointer and the CPU registers can be pushed onto and popped from the stack. Also, the C compiler should either provide in-line assembly or language extensions that allow you to enable and disable interrupts from C. µC/OS-II can run on most 8-bit, 16-bit, 32-bit or even 64-bit microprocessors or micro-controllers and, DSPs. All the ports that currently exist for µC/OS can be easily converted to µC/OS-II in about an hour. Also, because µC/OS-II is upward compatible with µC/OS, your µC/OS applications should run on µC/OS-II with few or no changes. Check for the availability of ports on the µC/OS-II Web site at ‘www.uCOS-II.com’.
ROMable: µC/OS-II was designed for embedded applications. This means that if you have the proper tool chain (i.e. C compiler, assembler and linker/locator), you can embed µC/OS-II as part of a product. Scalable: I designed µC/OS-II so that you can use only the services that you need in your application. This means that a product can have just a few of µC/OS-II’s services while another product can have the full set of features. This allows you to reduce the amount of memory (both RAM and ROM) needed by µC/OS-II on a product per product basis. Scalability is accomplished with the use of conditional compilation. You simply specify (through #define constants) which features you need for your application/product. I did everything I could to reduce both the code and data space required by µC/OS-II.
Preemptive: µC/OS-II is a fully-preemptive real-time kernel. This means that µC/OS-II always runs the highest priority task that is ready. Most commercial kernels are preemptive and µC/OS-II is comparable in performance with many of them. Multi-tasking: µC/OS-II can manage up to 64 tasks, however, the current version of the software reserves eight (8) of these tasks for system use. This leaves your application with up to 56 tasks. Each task has a unique priority assigned to it which means that µC/OS-II cannot do round robin scheduling. There are thus 64 priority levels. Deterministic: Execution time of all µC/OS-II functions and services are deterministic. This means that you can always know how much time µC/OS-II will take to execute a function or a service. Furthermore, except for one service, execution time of all µC/OS-II services do not depend on the number of tasks running in your application. Task stacks: Each task requires its own stack, however, µC/OS-II allows each task to have a different stack size. This allows you to reduce the amount of RAM needed in your application. With µC/OS-II’s stack checking feature, you can determine exactly how much stack space each task actually requires. Services: m C/OS-II provides a number of system services such as mailboxes, queues, semaphores, fixed-sized memory partitions, time related functions, etc. Interrupt Management: Interrupts can suspend the execution of a task and, if a higher priority task is awakened as a result of the interrupt, the highest priority task will run as soon as all nested interrupts complete. Interrupts can be nested up to 255 levels deep. Robust and reliable: µC/OS-II is based on µC/OS which has been used in hundreds of commercial applications since 1992. µC/OS-II uses the same core and most of the same functions as µC/OS yet offers more features.
Figures, Listings and Tables Convention: You will notice that when I reference a specific element in a figure, I use the letter ‘F’ followed by the figure number. A number in parenthesis following the figure number represents a specific element in the figure that I am trying to bring your attention to. F1-2(3) thus means look at the third item in Figure 1-2. Listings and tables work exactly the same way except that a listing start with the letter ‘L’ and a table with the letter ‘T’. Source Code Conventions: All µC/OS-II objects (functions, variables, #define constants and macros) start with OS indicating that they are Operating System related. Functions are found in alphabetical order in all the source code files. This allows you to quickly locate any function. You will find the coding style I use is very consistent. I have been adopting the K&R style for many years. However, I did add some of my own enhancements to make the code (I believe) easier to read and maintain. Indention is always 4 spaces, TABs are never used, always at least one space around an operator, comments are always to the right of code, comment blocks are used to describe functions, etc. The following table provides the acronyms, abbreviations and mnemonics (AAMs) used in this book. I combine some of these AAMs to make up function, variable and #define names in a hierarchical way. For example, the function OSMboxCreate() reads like this: the function is part of the operating system (OS), it is related to the mailbox services (Mbox) and the operation performed is to Create a mailbox. Also, all services that have similar operation share the same name. For e xample, OSSemCreate() and OSMboxCreate() perform the same operation but on their respective objects (i.e. semaphore and mailbox, respectively).
分享到:
收藏