├── Chapter02 └── hello │ ├── CMakeLists.txt │ └── hello.cpp ├── Chapter03 ├── alignment │ ├── CMakeLists.txt │ └── alignment.cpp ├── cache_align │ ├── CMakeLists.txt │ └── cache_align.cpp ├── enconv │ ├── CMakeLists.txt │ ├── receiver.cpp │ └── sender.cpp ├── endiannes │ ├── CMakeLists.txt │ └── endianness.cpp ├── fixed_types │ ├── CMakeLists.txt │ └── fixed_types.cpp ├── packed_alignment │ ├── CMakeLists.txt │ └── packed_alignment.cpp └── sizet │ ├── CMakeLists.txt │ └── sizet.cpp ├── Chapter04 ├── isr │ └── isr.c └── serial │ └── serial.c ├── Chapter05 ├── loop │ ├── CMakeLists.txt │ └── loop.cpp ├── loop2 │ ├── CMakeLists.txt │ └── loop.cpp └── loop3 │ ├── CMakeLists.txt │ └── loop.cpp ├── Chapter06 ├── objpool │ ├── CMakeLists.txt │ └── objpool.cpp ├── prealloc │ ├── CMakeLists.txt │ └── prealloc.cpp ├── ringbuf │ ├── CMakeLists.txt │ └── ringbuf.cpp ├── shmem │ ├── CMakeLists.txt │ └── shmem.cpp └── timer │ ├── CMakeLists.txt │ └── timer.cpp ├── Chapter07 ├── async │ ├── CMakeLists.txt │ └── async.cpp ├── atomic │ ├── CMakeLists.txt │ └── atomic.cpp ├── condvar │ ├── CMakeLists.txt │ └── condvar.cpp ├── lockfree │ ├── CMakeLists.txt │ └── lockfree.cpp ├── memorder │ ├── CMakeLists.txt │ └── memorder.cpp ├── mutex │ ├── CMakeLists.txt │ └── mutex.cpp ├── shmatomic │ ├── CMakeLists.txt │ └── shmatomic.cpp └── threads │ ├── CMakeLists.txt │ └── threads.cpp ├── Chapter08 ├── flat │ ├── CMakeLists.txt │ ├── ipc1.cpp │ ├── message.fbs │ └── message_generated.h ├── ipc1 │ ├── CMakeLists.txt │ └── ipc1.cpp ├── ipc2 │ ├── CMakeLists.txt │ ├── ipc1 │ └── ipc2.cpp ├── ipc3 │ ├── CMakeLists.txt │ └── ipc3.cpp ├── ipc4 │ ├── CMakeLists.txt │ └── ipc4.cpp └── stream │ ├── CMakeLists.txt │ └── stream.cpp ├── Chapter09 ├── gpio │ ├── CMakeLists.txt │ └── gpio.cpp ├── gpiod │ ├── CMakeLists.txt │ └── gpiod.cpp ├── i2c │ ├── CMakeLists.txt │ └── i2c.cpp ├── pwm │ ├── CMakeLists.txt │ └── pwm.cpp └── rtc │ ├── CMakeLists.txt │ └── rtc.cpp ├── Chapter10 └── udev │ ├── CMakeLists.txt │ └── udev.cpp ├── Chapter11 ├── chrono │ ├── CMakeLists.txt │ └── chrono.cpp ├── delays │ ├── CMakeLists.txt │ └── delays.cpp ├── interval │ ├── CMakeLists.txt │ └── interval.cpp ├── monotonic │ ├── CMakeLists.txt │ └── monotonic.cpp └── timestamps │ ├── CMakeLists.txt │ └── timestamps.cpp ├── Chapter12 ├── catch │ ├── CMakeLists.txt │ └── catch.cpp ├── debounce │ ├── CMakeLists.txt │ └── debounce.cpp ├── errcode │ ├── CMakeLists.txt │ └── errcode.cpp ├── except │ ├── CMakeLists.txt │ └── except.cpp ├── heartbeat │ ├── CMakeLists.txt │ └── heartbeat.cpp ├── static │ ├── CMakeLists.txt │ └── static.cpp └── watchdog │ ├── CMakeLists.txt │ └── watchdog.cpp ├── Chapter13 ├── array │ ├── CMakeLists.txt │ └── array.cpp ├── expected │ ├── CMakeLists.txt │ └── expected.cpp ├── pinthreads │ ├── CMakeLists.txt │ └── pinthreads.cpp └── realtime │ ├── CMakeLists.txt │ └── realtime.cpp ├── Chapter14 ├── assert │ ├── CMakeLists.txt │ └── assert.cpp └── returns │ ├── CMakeLists.txt │ └── returns.cpp ├── Chapter15 └── snippet.cpp ├── LICENSE └── README.md /Chapter02/hello/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(hello) 3 | add_executable(hello hello.cpp) 4 | 5 | #set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabi-gcc) 6 | #set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 7 | #set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 8 | #set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 9 | #set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 10 | #set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 11 | -------------------------------------------------------------------------------- /Chapter02/hello/hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Hello, world!" << std::endl; 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /Chapter03/alignment/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(alignment) 3 | add_executable(alignment alignment.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | #set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | 11 | -------------------------------------------------------------------------------- /Chapter03/alignment/alignment.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum class Category: uint8_t { 4 | file, directory, socket 5 | }; 6 | 7 | struct ObjectMetadata1 { 8 | uint8_t access_flags; 9 | uint32_t size; 10 | uint32_t owner_id; 11 | Category category; 12 | }; 13 | 14 | struct ObjectMetadata2 { 15 | uint32_t size; 16 | uint32_t owner_id; 17 | uint8_t access_flags; 18 | Category category; 19 | }; 20 | 21 | int main() { 22 | ObjectMetadata1 object_pool1[1000]; 23 | ObjectMetadata2 object_pool2[1000]; 24 | std::cout << "Poorly aligned:" << sizeof(object_pool1) << std::endl; 25 | std::cout << "Well aligned:" << sizeof(object_pool2) << std::endl; 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /Chapter03/cache_align/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(cache_align) 3 | add_executable(cache_align cache_align.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGSE "--std=c++11") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | -------------------------------------------------------------------------------- /Chapter03/cache_align/cache_align.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | constexpr int kAlignSize = 128; 5 | constexpr int kAllocBytes = 256; 6 | 7 | constexpr int overlap(void* ptr) { 8 | size_t addr = (size_t)ptr; 9 | return addr & (kAlignSize - 1); 10 | } 11 | 12 | int main() { 13 | char static_buffer[kAllocBytes]; 14 | char* dynamic_buffer = new char[kAllocBytes]; 15 | printf("Static buffer address: %p (%d)\n", static_buffer, 16 | overlap(static_buffer)); 17 | printf("Dynamic buffer address: %p (%d)\n", dynamic_buffer, 18 | overlap(dynamic_buffer)); 19 | delete[] dynamic_buffer; 20 | 21 | alignas(kAlignSize) char aligned_static_buffer[kAllocBytes]; 22 | char* aligned_dynamic_buffer = nullptr; 23 | if (posix_memalign((void**)&aligned_dynamic_buffer, 24 | kAlignSize, kAllocBytes)) { 25 | printf("Failed to allocate aligned memory buffer\n"); 26 | } 27 | printf("Aligned static buffer address: %p (%d)\n", aligned_static_buffer, 28 | overlap(aligned_static_buffer)); 29 | printf("Aligned dynamic buffer address: %p (%d)\n", aligned_dynamic_buffer, 30 | overlap(aligned_dynamic_buffer)); 31 | free(aligned_dynamic_buffer); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /Chapter03/enconv/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(enconv) 3 | add_executable(sender sender.cpp) 4 | add_executable(receiver receiver.cpp) 5 | 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | set(CMAKE_SYSTEM_PROCESSOR arm) 8 | 9 | SET(CMAKE_CXX_FLAGS "--std=c++14") 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | 13 | -------------------------------------------------------------------------------- /Chapter03/enconv/receiver.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void ReadData(int fd, void* ptr, size_t size) { 12 | size_t offset =0; 13 | while (size) { 14 | char *buffer = (char*)ptr + offset; 15 | int received = read(fd, buffer, size); 16 | if (received < 0) { 17 | throw std::runtime_error("Can not read from file"); 18 | } else if (received == 0) { 19 | throw std::runtime_error("No more data"); 20 | } 21 | offset += received; 22 | size -= received; 23 | } 24 | } 25 | 26 | std::string ReadMessage(int fd) { 27 | uint32_t encoded_size = 0; 28 | ReadData(fd, &encoded_size, sizeof(encoded_size)); 29 | uint32_t size = ntohl(encoded_size); 30 | auto data = std::make_unique(size); 31 | ReadData(fd, data.get(), size); 32 | return std::string(data.get(), size); 33 | } 34 | 35 | int main(void) { 36 | int fd = open("envconv.data", O_RDONLY, 0666); 37 | while(true) { 38 | try { 39 | auto s = ReadMessage(fd); 40 | std::cout << "Read: " << s << std::endl; 41 | } catch(const std::runtime_error& e) { 42 | std::cout << e.what() << std::endl; 43 | break; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Chapter03/enconv/sender.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void WriteData(int fd, const void* ptr, size_t size) { 9 | size_t offset =0; 10 | while (size) { 11 | const char *buffer = (const char*)ptr + offset; 12 | int written = write(fd, buffer, size); 13 | if (written < 0) { 14 | throw std::runtime_error("Can not write to file"); 15 | } 16 | offset += written; 17 | size -= written; 18 | } 19 | } 20 | 21 | void WriteMessage(int fd, const char* str) { 22 | uint32_t size = strlen(str); 23 | uint32_t encoded_size = htonl(size); 24 | WriteData(fd, &encoded_size, sizeof(encoded_size)); 25 | WriteData(fd, str, size); 26 | } 27 | 28 | int main(int argc, char** argv) { 29 | int fd = open("envconv.data", O_WRONLY|O_APPEND|O_CREAT, 0666); 30 | for (int i = 1; i < argc; i++) { 31 | WriteMessage(fd, argv[i]); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Chapter03/endiannes/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(endianness) 3 | add_executable(endianness endianness.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | -------------------------------------------------------------------------------- /Chapter03/endiannes/endianness.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | union { 5 | uint32_t i; 6 | uint8_t c[4]; 7 | } data; 8 | data.i = 0x01020304; 9 | if (data.c[0] == 0x01) { 10 | std::cout << "Big-endian" << std::endl; 11 | } else { 12 | std::cout << "Little-endian" << std::endl; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Chapter03/fixed_types/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(fixed_types) 3 | add_executable(fixed_types fixed_types.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | -------------------------------------------------------------------------------- /Chapter03/fixed_types/fixed_types.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void SendDataToDevice(void* buffer, uint32_t size) { 4 | // This is a stub function to send data pointer by 5 | // buffer. 6 | std::cout << "Sending data chunk of size " << size << std::endl; 7 | } 8 | 9 | int main() { 10 | char buffer[] = "Hello, world!"; 11 | uint32_t size = sizeof(buffer); 12 | SendDataToDevice(&size, sizeof(size)); 13 | SendDataToDevice(buffer, size); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter03/packed_alignment/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(packed_alignment) 3 | add_executable(packed_alignment packed_alignment.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | -------------------------------------------------------------------------------- /Chapter03/packed_alignment/packed_alignment.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum class Category: uint8_t { 4 | file, directory, socket 5 | }; 6 | 7 | struct ObjectMetadata1 { 8 | uint8_t access_flags; 9 | uint32_t size; 10 | uint32_t owner_id; 11 | Category category; 12 | } __attribute__((packed)); 13 | 14 | struct ObjectMetadata2 { 15 | uint32_t size; 16 | uint32_t owner_id; 17 | uint8_t access_flags; 18 | Category category; 19 | } __attribute__((packed)); 20 | 21 | int main() { 22 | ObjectMetadata1 object_pool1[1000]; 23 | ObjectMetadata2 object_pool2[1000]; 24 | std::cout << "Poorly aligned:" << sizeof(object_pool1) << std::endl; 25 | std::cout << "Well aligned:" << sizeof(object_pool2) << std::endl; 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /Chapter03/sizet/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(sizet) 3 | add_executable(sizet sizet.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | 11 | -------------------------------------------------------------------------------- /Chapter03/sizet/sizet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void StoreData(const char* buffer, size_t size) { 4 | std::cout << "Store " << size << " bytes of data" << std::endl; 5 | } 6 | 7 | int main() { 8 | char data[] = "Hello,\x1b\a\x03world!"; 9 | const char *buffer = data; 10 | std::cout << "Size of buffer pointer is " << sizeof(buffer) << std::endl; 11 | std::cout << "Size of int is " << sizeof(int) << std::endl; 12 | std::cout << "Size of size_t is " << sizeof(size_t) << std::endl; 13 | StoreData(data, sizeof(data)); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter04/isr/isr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | volatile int Counter = 0; 4 | void timer0_ISR (void) __interrupt(1) //interrupt no. 1 for Timer0 5 | { 6 | 7 | Counter++; 8 | } 9 | 10 | void main(void) 11 | { 12 | TMOD = 0x03; 13 | TH0 = 0x0; 14 | TL0 = 0x0; 15 | ET0 = 1; 16 | TR0 = 1; 17 | EA = 1; 18 | while (1); // do nothing 19 | } 20 | -------------------------------------------------------------------------------- /Chapter04/serial/serial.c: -------------------------------------------------------------------------------- 1 | #include<8051.h> 2 | 3 | unsigned char receivedChar=0; 4 | 5 | void serial_isr() __interrupt(4) { 6 | if(RI == 1) { 7 | P0 = SBUF; 8 | RI = 0; 9 | } else if(TI == 1) { 10 | TI = 0; 11 | } 12 | } 13 | 14 | 15 | void main() { 16 | SCON = 0x50; 17 | TMOD = 0x20; 18 | TH1 = 0xFD; 19 | TR1 = 1; 20 | ES = 1; 21 | EA = 1; 22 | 23 | while(1); 24 | } -------------------------------------------------------------------------------- /Chapter05/loop/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(loop) 3 | add_executable(loop loop.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | #set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "-g --std=c++14") 9 | 10 | #set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabi-gcc) 11 | #set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 14 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 15 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 16 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 17 | -------------------------------------------------------------------------------- /Chapter05/loop/loop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void runner(std::chrono::milliseconds limit, 7 | std::function fn, 8 | int value) { 9 | auto start = std::chrono::system_clock::now(); 10 | fn(value); 11 | auto end = std::chrono::system_clock::now(); 12 | std::chrono::milliseconds delta = 13 | std::chrono::duration_cast(end - start); 14 | if (delta > limit) { 15 | throw std::runtime_error("Time limit exceeded"); 16 | } 17 | } 18 | 19 | void delay_ms(int count) { 20 | for (int i = 0; i < count; i++) { 21 | std::this_thread::sleep_for(std::chrono::microseconds(1050)); 22 | } 23 | } 24 | 25 | 26 | int main() { 27 | int max_delay = 10; 28 | for (int i = 0; i < max_delay; i++) { 29 | runner(std::chrono::milliseconds(max_delay), delay_ms, i); 30 | } 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /Chapter05/loop2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(loop) 3 | add_executable(loop loop.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | #set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS_RELEASE "--std=c++11") 9 | SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_RELEASE} -g -DDEBUG") 10 | 11 | set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabi-gcc) 12 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 13 | 14 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 15 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 16 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 17 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 18 | -------------------------------------------------------------------------------- /Chapter05/loop2/loop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | void runner(std::chrono::milliseconds limit, 9 | std::function fn, 10 | int value) { 11 | auto start = std::chrono::system_clock::now(); 12 | fn(value); 13 | auto end = std::chrono::system_clock::now(); 14 | std::chrono::milliseconds delta = 15 | std::chrono::duration_cast(end - start); 16 | syslog(LOG_DEBUG, "Delta is %ld", 17 | static_cast(delta.count())); 18 | if (delta > limit) { 19 | syslog(LOG_ERR, "Execution time %ld ms exceeded %ld ms limit", 20 | static_cast(delta.count()), 21 | static_cast(limit.count())); 22 | throw std::runtime_error("Time limit exceeded"); 23 | } 24 | } 25 | 26 | void delay_ms(int count) { 27 | for (int i = 0; i < count; i++) { 28 | std::this_thread::sleep_for(std::chrono::microseconds(1050)); 29 | } 30 | } 31 | 32 | 33 | int main() { 34 | openlog("loop3", LOG_PERROR, LOG_USER); 35 | int max_delay = 10; 36 | for (int i = 0; i < max_delay; i++) { 37 | runner(std::chrono::milliseconds(max_delay), delay_ms, i); 38 | } 39 | closelog(); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /Chapter05/loop3/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(loop) 3 | add_executable(loop loop.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | #set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS_RELEASE "--std=c++11") 9 | SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_RELEASE} -g -DDEBUG") 10 | 11 | #set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabi-gcc) 12 | #set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 13 | 14 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 15 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 16 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 17 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 18 | -------------------------------------------------------------------------------- /Chapter05/loop3/loop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | #ifdef DEBUG 9 | #define LOG_DEBUG(fmt, args...) fprintf(stderr, fmt, args) 10 | #else 11 | #define LOG_DEBUG(fmt, args...) 12 | #endif 13 | 14 | 15 | void runner(std::chrono::milliseconds limit, 16 | std::function fn, 17 | int value) { 18 | auto start = std::chrono::system_clock::now(); 19 | fn(value); 20 | auto end = std::chrono::system_clock::now(); 21 | std::chrono::milliseconds delta = 22 | std::chrono::duration_cast(end - start); 23 | LOG_DEBUG("Delay: %ld ms, max: %ld ms\n", 24 | static_cast(delta.count()), 25 | static_cast(limit.count())); 26 | if (delta > limit) { 27 | throw std::runtime_error("Time limit exceeded"); 28 | } 29 | } 30 | 31 | void delay_ms(int count) { 32 | for (int i = 0; i < count; i++) { 33 | std::this_thread::sleep_for(std::chrono::microseconds(1050)); 34 | } 35 | } 36 | 37 | 38 | int main() { 39 | int max_delay = 10; 40 | for (int i = 0; i < max_delay; i++) { 41 | runner(std::chrono::milliseconds(max_delay), delay_ms, i); 42 | } 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /Chapter06/objpool/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(objpool) 3 | add_executable(objpool objpool.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | 11 | -------------------------------------------------------------------------------- /Chapter06/objpool/objpool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class ObjectPool { 5 | private: 6 | T objects[N]; 7 | size_t available[N]; 8 | size_t top = 0; 9 | public: 10 | ObjectPool(): top(0) { 11 | for (size_t i = 0; i < N; i++) { 12 | available[i] = i; 13 | } 14 | } 15 | 16 | T& get() { 17 | if (top < N) { 18 | size_t idx = available[top++]; 19 | return objects[idx]; 20 | } else { 21 | throw std::runtime_error("All objects are in use"); 22 | } 23 | } 24 | 25 | void free(const T& obj) { 26 | const T* ptr = &obj; 27 | size_t idx = (ptr - objects) / sizeof(T); 28 | if (idx < N) { 29 | if (top) { 30 | objects[idx].deinit(); 31 | top--; 32 | available[top] = idx; 33 | } else { 34 | throw std::runtime_error("Some object was freed more than once"); 35 | } 36 | } else { 37 | throw std::runtime_error("Freeing object that does not belong to the pool"); 38 | } 39 | } 40 | size_t requested() const { return top; } 41 | }; 42 | 43 | 44 | struct Point { 45 | int x, y; 46 | void deinit() { std::cout << "Hello " << x << ", " << y << "\n"; } 47 | }; 48 | 49 | int main() { 50 | ObjectPool points; 51 | 52 | Point& a = points.get(); 53 | a.x = 10; a.y=20; 54 | std::cout << "Point a (" << a.x << ", " << a.y << ") initialized, requested " << 55 | points.requested() << std::endl; 56 | 57 | Point& b = points.get(); 58 | std::cout << "Point b (" << b.x << ", " << b.y << ") not initialized, requested " << 59 | points.requested() << std::endl; 60 | 61 | points.free(a); 62 | std::cout << "Point a(" << a.x << ", " << a.y << ") returned, requested " << 63 | points.requested() << std::endl; 64 | 65 | Point& c = points.get(); 66 | std::cout << "Point c(" << c.x << ", " << c.y << ") not intialized, requested " << 67 | points.requested() << std::endl; 68 | 69 | Point local; 70 | try { 71 | points.free(local); 72 | } catch (std::runtime_error e) { 73 | std::cout << "Exception caught: " << e.what() << std::endl; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Chapter06/prealloc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(prealloc) 3 | add_executable(prealloc prealloc.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++17") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter06/prealloc/prealloc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | constexpr size_t kMaxFileNameSize = 256; 5 | constexpr size_t kBufferSize = 4096; 6 | constexpr size_t kMaxDevices = 16; 7 | 8 | class SerialDevice { 9 | char device_file_name[256]; 10 | uint8_t input_buffer[kBufferSize]; 11 | uint8_t output_buffer[kBufferSize]; 12 | int file_descriptor; 13 | size_t input_length; 14 | size_t output_length; 15 | 16 | public: 17 | SerialDevice(): 18 | file_descriptor(-1), input_length(0), output_length(0) {} 19 | 20 | bool Init(const char* name) { 21 | strncpy(device_file_name, name, sizeof(device_file_name)); 22 | } 23 | 24 | bool Write(const uint8_t* data, size_t size) { 25 | if (size > sizeof(output_buffer)) { 26 | throw "Data size exceeds the limit"; 27 | } 28 | memcpy(output_buffer, data, size); 29 | } 30 | 31 | size_t Read(uint8_t* data, size_t size) { 32 | if (size < input_length) { 33 | throw "Read buffer is too small"; 34 | } 35 | memcpy(data, input_buffer, input_length); 36 | return input_length; 37 | } 38 | 39 | }; 40 | 41 | int main() { 42 | SerialDevice devices[kMaxDevices]; 43 | size_t number_of_devices = 0; 44 | 45 | uint8_t data[] = "Hello"; 46 | devices[0].Init("test"); 47 | devices[0].Write(data, sizeof(data)); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /Chapter06/ringbuf/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(ringbuf) 3 | add_executable(ringbuf ringbuf.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter06/ringbuf/ringbuf.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class RingBuffer { 5 | private: 6 | T objects[N]; 7 | size_t read; 8 | size_t write; 9 | size_t queued; 10 | public: 11 | RingBuffer(): read(0), write(0), queued(0) {} 12 | 13 | T& push() { 14 | T& current = objects[write]; 15 | write = (write + 1) % N; 16 | queued++; 17 | if (queued > N) { 18 | queued = N; 19 | read = write; 20 | } 21 | return current; 22 | } 23 | 24 | const T& pull() { 25 | if (!queued) { 26 | throw std::runtime_error("No data in the ring buffer"); 27 | } 28 | T& current = objects[read]; 29 | read = (read + 1) % N; 30 | queued--; 31 | return current; 32 | } 33 | 34 | bool has_data() { 35 | return queued != 0; 36 | } 37 | }; 38 | 39 | struct Frame { 40 | uint32_t index; 41 | uint8_t data[1024]; 42 | }; 43 | 44 | int main() { 45 | RingBuffer frames; 46 | 47 | std::cout << "Frames " << (frames.has_data() ? "" : "do not ") 48 | << "contain data" << std::endl; 49 | try { 50 | const Frame& frame = frames.pull(); 51 | } catch (std::runtime_error e) { 52 | std::cout << "Exception caught: " << e.what() << std::endl; 53 | } 54 | 55 | for (size_t i = 0; i < 5; i++) { 56 | Frame& out = frames.push(); 57 | out.index = i; 58 | out.data[0] = 'a' + i; 59 | out.data[1] = '\0'; 60 | } 61 | std::cout << "Frames " << (frames.has_data() ? "" : "do not ") 62 | << "contain data" << std::endl; 63 | while (frames.has_data()) { 64 | const Frame& in = frames.pull(); 65 | std::cout << "Frame " << in.index << ": " << in.data << std::endl; 66 | } 67 | 68 | for (size_t i = 0; i < 26; i++) { 69 | Frame& out = frames.push(); 70 | out.index = i; 71 | out.data[0] = 'a' + i; 72 | out.data[1] = '\0'; 73 | } 74 | std::cout << "Frames " << (frames.has_data() ? "" : "do not ") 75 | << "contain data" << std::endl; 76 | while (frames.has_data()) { 77 | const Frame& in = frames.pull(); 78 | std::cout << "Frame " << in.index << ": " << in.data << std::endl; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Chapter06/shmem/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(shmem) 3 | add_executable(shmem shmem.cpp) 4 | target_link_libraries(shmem rt) 5 | 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | set(CMAKE_SYSTEM_PROCESSOR arm) 8 | 9 | SET(CMAKE_CXX_FLAGS "--std=c++14") 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter06/shmem/shmem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | const char* kSharedMemPath = "/sample_point"; 11 | const size_t kPayloadSize = 16; 12 | 13 | using namespace std::literals; 14 | 15 | template 16 | class SharedMem { 17 | int fd; 18 | T* ptr; 19 | const char* name; 20 | 21 | public: 22 | SharedMem(const char* name, bool owner=false) { 23 | fd = shm_open(name, O_RDWR | O_CREAT, 0600); 24 | if (fd == -1) { 25 | throw std::runtime_error("Failed to open a shared memory region"); 26 | } 27 | if (ftruncate(fd, sizeof(T)) < 0) { 28 | close(fd); 29 | throw std::runtime_error("Failed to set size of a shared memory region"); 30 | }; 31 | ptr = (T*)mmap(nullptr, sizeof(T), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 32 | if (!ptr) { 33 | close(fd); 34 | throw std::runtime_error("Failed to mmap a shared memory region"); 35 | } 36 | this->name = owner ? name : nullptr; 37 | std::cout << "Opened shared mem instance " << name << std::endl; 38 | } 39 | 40 | ~SharedMem() { 41 | munmap(ptr, sizeof(T)); 42 | close(fd); 43 | if (name) { 44 | std::cout << "Remove shared mem instance " << name << std::endl; 45 | shm_unlink(name); 46 | } 47 | } 48 | 49 | T& get() const { 50 | return *ptr; 51 | } 52 | }; 53 | 54 | 55 | struct Payload { 56 | uint32_t index; 57 | uint8_t raw[kPayloadSize]; 58 | }; 59 | 60 | 61 | void producer() { 62 | SharedMem writer(kSharedMemPath); 63 | Payload& pw = writer.get(); 64 | for (int i = 0; i < 5; i++) { 65 | pw.index = i; 66 | std::fill_n(pw.raw, sizeof(pw.raw) - 1, 'a' + i); 67 | pw.raw[sizeof(pw.raw) - 1] = '\0'; 68 | std::this_thread::sleep_for(150ms); 69 | } 70 | } 71 | 72 | void consumer() { 73 | SharedMem point_reader(kSharedMemPath, true); 74 | Payload& pr = point_reader.get(); 75 | for (int i = 0; i < 10; i++) { 76 | std::cout << "Read data frame " << pr.index << ": " << pr.raw << std::endl; 77 | std::this_thread::sleep_for(100ms); 78 | } 79 | } 80 | 81 | int main() { 82 | 83 | if (fork()) { 84 | consumer(); 85 | } else { 86 | producer(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Chapter06/timer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(timer) 3 | add_executable(timer timer.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter06/timer/timer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | 10 | constexpr uint32_t kTimerBase = 0x3F003000; 11 | 12 | struct SystemTimer { 13 | uint32_t CS; 14 | uint32_t counter_lo; 15 | uint32_t counter_hi; 16 | }; 17 | 18 | 19 | int main() { 20 | 21 | int memfd = open("/dev/mem", O_RDWR | O_SYNC); 22 | if (memfd < 0) { 23 | throw std::system_error(errno, std::generic_category(), 24 | "Failed to open /dev/mem. Make sure you run as root."); 25 | } 26 | 27 | SystemTimer *timer = (SystemTimer*)mmap(NULL, sizeof(SystemTimer), 28 | PROT_READ|PROT_WRITE, MAP_SHARED, 29 | memfd, kTimerBase); 30 | if (timer == MAP_FAILED) { 31 | throw std::system_error(errno, std::generic_category(), 32 | "Memory mapping failed"); 33 | } 34 | 35 | uint64_t prev = 0; 36 | for (int i = 0; i < 10; i++) { 37 | uint64_t time = ((uint64_t)timer->counter_hi << 32) + timer->counter_lo; 38 | std::cout << "System timer: " << time; 39 | if (i > 0) { 40 | std::cout << ", diff " << time - prev; 41 | } 42 | prev = time; 43 | std::cout << std::endl; 44 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 45 | } 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /Chapter07/async/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(async) 3 | add_executable(async async.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++14") 9 | target_link_libraries(async pthread -static-libstdc++) 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter07/async/async.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int calculate (int x) { 6 | auto start = std::chrono::system_clock::now(); 7 | std::cout << "Start calculation\n"; 8 | std::this_thread::sleep_for(std::chrono::seconds(1)); 9 | auto delta = std::chrono::system_clock::now() - start; 10 | auto ms = std::chrono::duration_cast(delta); 11 | std::cout << "Done in " << ms.count() << " ms\n"; 12 | return x*x; 13 | } 14 | 15 | void test(int value, int worktime) { 16 | std::cout << "Request result of caclulations for " << value << std::endl; 17 | std::future fut = std::async (calculate, value); 18 | std::cout << "Keep working for " << worktime << " ms" << std::endl; 19 | std::this_thread::sleep_for(std::chrono::milliseconds(worktime)); 20 | auto start = std::chrono::system_clock::now(); 21 | std::cout << "Waiting for result" << std::endl; 22 | int result = fut.get(); 23 | auto delta = std::chrono::system_clock::now() - start; 24 | auto ms = std::chrono::duration_cast(delta); 25 | 26 | std::cout << "Result is " << result 27 | << ", waited for " << ms.count() << " ms" 28 | << std::endl << std::endl; 29 | } 30 | 31 | int main () 32 | { 33 | test(5, 400); 34 | test(8, 1200); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /Chapter07/atomic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(atomic) 3 | add_executable(atomic atomic.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | target_link_libraries(atomic pthread) 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter07/atomic/atomic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::atomic shared_index{0}; 8 | std::vector data; 9 | 10 | void worker(int index, int timeout) { 11 | while(true) { 12 | size_t worker_index = shared_index.fetch_add(1); 13 | if (worker_index >= data.size()) { 14 | break; 15 | } 16 | std::cout << "Worker " << index << " handles " << worker_index << std::endl; 17 | data[worker_index] = data[worker_index] * 2; 18 | std::this_thread::sleep_for(std::chrono::milliseconds(timeout)); 19 | } 20 | } 21 | 22 | int main() { 23 | for (int i = 0; i < 10; i++) { 24 | data.emplace_back(i); 25 | } 26 | std::thread worker1(worker, 1, 50); 27 | std::thread worker2(worker, 2, 20); 28 | worker1.join(); 29 | worker2.join(); 30 | std::cout << "Result: "; 31 | for (auto& v : data) { 32 | std::cout << v << ' '; 33 | } 34 | std::cout << std::endl; 35 | } 36 | -------------------------------------------------------------------------------- /Chapter07/condvar/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(condvar) 3 | add_executable(condvar condvar.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | target_link_libraries(condvar pthread) 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter07/condvar/condvar.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::mutex m; 8 | std::condition_variable cv; 9 | std::vector result; 10 | int next = 0; 11 | 12 | void worker(int index) { 13 | for (int i = 0; i < 10; i++) { 14 | std::unique_lock l(m); 15 | cv.wait(l, [=]{return next == index; }); 16 | std::cout << "worker " << index << "\n"; 17 | result.push_back(index); 18 | next = next + 1; 19 | if (next > 2) { next = 1; }; 20 | cv.notify_all(); 21 | } 22 | } 23 | 24 | int main() { 25 | std::thread worker1(worker, 1); 26 | std::thread worker2(worker, 2); 27 | { 28 | std::lock_guard l(m); 29 | next = 1; 30 | } 31 | std::cout << "Start\n"; 32 | cv.notify_all(); 33 | worker1.join(); 34 | worker2.join(); 35 | for (int e : result) { 36 | std::cout << e << ' '; 37 | } 38 | std::cout << std::endl; 39 | } 40 | -------------------------------------------------------------------------------- /Chapter07/lockfree/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(lockfree) 3 | add_executable(lockfree lockfree.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | target_link_libraries(lockfree pthread) 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter07/lockfree/lockfree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node { 5 | int data; 6 | Node* next; 7 | }; 8 | 9 | class Stack { 10 | std::atomic top; 11 | 12 | public: 13 | Stack(): top(nullptr) { 14 | std::cout << "Stack is " << 15 | (top.is_lock_free() ? "" : "not ") 16 | << "lock-free" << std::endl; 17 | } 18 | 19 | void Push(int data) { 20 | Node* new_node = new Node{data, nullptr}; 21 | new_node->next = top.load(); 22 | while(!std::atomic_compare_exchange_weak( 23 | &top, 24 | &new_node->next, 25 | new_node)); 26 | } 27 | }; 28 | 29 | int main() { 30 | Stack s; 31 | s.Push(1); 32 | } 33 | -------------------------------------------------------------------------------- /Chapter07/memorder/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(memorder) 3 | add_executable(memorder memorder.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | target_link_libraries(memorder pthread) 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter07/memorder/memorder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::atomic running{true}; 8 | std::atomic counter{0}; 9 | 10 | void worker() { 11 | while(running) { 12 | counter.fetch_add(1, std::memory_order_relaxed); 13 | } 14 | } 15 | 16 | int main() { 17 | std::thread worker1(worker); 18 | std::thread worker2(worker); 19 | std::this_thread::sleep_for(std::chrono::seconds(1)); 20 | running = false; 21 | worker1.join(); 22 | worker2.join(); 23 | std::cout << "Counter: " << counter << std::endl; 24 | } 25 | -------------------------------------------------------------------------------- /Chapter07/mutex/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(mutex) 3 | add_executable(mutex mutex.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | target_link_libraries(mutex pthread) 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter07/mutex/mutex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::mutex m; 7 | 8 | void worker(int index) { 9 | for (int i = 0; i < 10; i++) { 10 | { 11 | std::lock_guard g(m); 12 | std::cout << "Worker " << index << " begins" << std::endl; 13 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 14 | std::cout << "Worker " << index << " ends" << std::endl; 15 | } 16 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); 17 | } 18 | } 19 | 20 | int main() { 21 | std::thread worker1(worker, 1); 22 | std::thread worker2(worker, 2); 23 | worker1.join(); 24 | worker2.join(); 25 | std::cout << "Done" << std::endl; 26 | } 27 | -------------------------------------------------------------------------------- /Chapter07/shmatomic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(shmatomic) 3 | add_executable(shmatomic shmatomic.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | target_link_libraries(shmatomic pthread rt) 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter07/shmatomic/shmatomic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | const char* kSharedMemPath = "/sample_point"; 11 | 12 | template 13 | class SharedMem { 14 | int fd; 15 | T* ptr; 16 | const char* name; 17 | 18 | public: 19 | SharedMem(const char* name, bool owner=false) { 20 | fd = shm_open(name, O_RDWR | O_CREAT, 0600); 21 | if (fd == -1) { 22 | throw std::runtime_error("Failed to open a shared memory region"); 23 | } 24 | if (ftruncate(fd, sizeof(T)) < 0) { 25 | close(fd); 26 | throw std::runtime_error("Failed to set size of a shared memory region"); 27 | }; 28 | ptr = (T*)mmap(nullptr, sizeof(T), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 29 | if (!ptr) { 30 | close(fd); 31 | throw std::runtime_error("Failed to mmap a shared memory region"); 32 | } 33 | this->name = owner ? name : nullptr; 34 | } 35 | 36 | ~SharedMem() { 37 | munmap(ptr, sizeof(T)); 38 | close(fd); 39 | if (name) { 40 | std::cout << "Remove shared mem instance " << name << std::endl; 41 | shm_unlink(name); 42 | } 43 | } 44 | 45 | T& get() const { 46 | return *ptr; 47 | } 48 | }; 49 | 50 | 51 | struct Payload { 52 | std::atomic_bool data_ready; 53 | std::atomic_bool data_processed; 54 | int index; 55 | }; 56 | 57 | 58 | void producer() { 59 | SharedMem writer(kSharedMemPath); 60 | Payload& pw = writer.get(); 61 | if (!pw.data_ready.is_lock_free()) { 62 | throw std::runtime_error("Timestamp is not lock-free"); 63 | } 64 | for (int i = 0; i < 10; i++) { 65 | pw.data_processed.store(false); 66 | pw.index = i; 67 | pw.data_ready.store(true); 68 | while(!pw.data_processed.load()); 69 | } 70 | } 71 | 72 | void consumer() { 73 | SharedMem point_reader(kSharedMemPath, true); 74 | Payload& pr = point_reader.get(); 75 | if (!pr.data_ready.is_lock_free()) { 76 | throw std::runtime_error("Timestamp is not lock-free"); 77 | } 78 | for (int i = 0; i < 10; i++) { 79 | while(!pr.data_ready.load()); 80 | pr.data_ready.store(false); 81 | std::cout << "Processing data chunk " << pr.index << std::endl; 82 | pr.data_processed.store(true); 83 | } 84 | } 85 | 86 | int main() { 87 | 88 | if (fork()) { 89 | consumer(); 90 | } else { 91 | producer(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Chapter07/threads/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(threads) 3 | add_executable(threads threads.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | target_link_libraries(threads pthread) 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter07/threads/threads.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void worker(int index) { 6 | for (int i = 0; i < 10; i++) { 7 | std::cout << "Worker " << index << " begins" << std::endl; 8 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 9 | std::cout << "Worker " << index << " ends" << std::endl; 10 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); 11 | } 12 | } 13 | 14 | int main() { 15 | std::thread worker1(worker, 1); 16 | std::thread worker2(worker, 2); 17 | worker1.join(); 18 | worker2.join(); 19 | std::cout << "Done" << std::endl; 20 | } 21 | -------------------------------------------------------------------------------- /Chapter08/flat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(flat) 3 | add_executable(flat ipc1.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | target_link_libraries(flat rt flatbuffers) 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter08/flat/ipc1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "message_generated.h" 13 | 14 | std::string kQueueName = "/test2"; 15 | 16 | class MessageQueue { 17 | private: 18 | mqd_t handle; 19 | public: 20 | MessageQueue(const std::string& name, int flags) { 21 | handle = mq_open(name.c_str(), flags); 22 | if (handle < 0) { 23 | throw std::runtime_error("Failed to open a queue for writing"); 24 | } 25 | } 26 | 27 | MessageQueue(const std::string& name, int flags, int max_count, int max_size) { 28 | struct mq_attr attrs = { 0, max_count, max_size, 0 }; 29 | handle = mq_open(name.c_str(), flags | O_CREAT, 0666, &attrs); 30 | if (handle < 0) { 31 | throw std::runtime_error("Failed to create a queue"); 32 | } 33 | } 34 | 35 | ~MessageQueue() { 36 | mq_close(handle); 37 | } 38 | 39 | void Send(const char* data, size_t len) { 40 | if (mq_send(handle, data, len, 0) < 0) { 41 | throw std::runtime_error("Failed to send a message"); 42 | } 43 | } 44 | 45 | void Receive(char* data, size_t len) { 46 | if (mq_receive(handle, data, len, 0) < len) { 47 | throw std::runtime_error("Failed to receive a message"); 48 | } 49 | } 50 | }; 51 | 52 | template 53 | class Writer { 54 | private: 55 | MessageQueue queue; 56 | public: 57 | Writer(std::string& name): 58 | queue(name, O_WRONLY) {} 59 | 60 | void Write(const T& data) { 61 | queue.Send(reinterpret_cast(&data), sizeof(data)); 62 | } 63 | }; 64 | 65 | template 66 | class Reader { 67 | private: 68 | MessageQueue queue; 69 | void (*func)(const T&); 70 | public: 71 | Reader(std::string& name, void (*func)(const T&)): 72 | queue(name, O_RDONLY), func(func) {} 73 | 74 | void Run() { 75 | T data; 76 | while(true) { 77 | queue.Receive(reinterpret_cast(&data), sizeof(data)); 78 | func(data); 79 | } 80 | } 81 | }; 82 | 83 | std::ostream& operator<<(std::ostream& o, const Message& m) { 84 | o << "(x=" << m.x() << ", y=" << m.y() << ")"; 85 | } 86 | 87 | void DoWrites() { 88 | std::vector messages {{1, 0}, {0, 1}, {1, 1}, {0, 0}}; 89 | Writer writer(kQueueName); 90 | for (const auto& m : messages) { 91 | std::cout << "Write " << m << std::endl; 92 | writer.Write(m); 93 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 94 | } 95 | } 96 | 97 | void DoReads() { 98 | Reader logger(kQueueName, [](const Message& data) { 99 | std::cout << "Received coordinate " << data << std::endl; 100 | }); 101 | logger.Run(); 102 | } 103 | 104 | 105 | int main(int argc, char** argv) { 106 | MessageQueue q(kQueueName, O_WRONLY, 10, sizeof(Message)); 107 | pid_t pid = fork(); 108 | if (pid) { 109 | DoWrites(); 110 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 111 | kill(pid, SIGTERM); 112 | } else { 113 | DoReads(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Chapter08/flat/message.fbs: -------------------------------------------------------------------------------- 1 | struct Message { 2 | x: int; 3 | y: int; 4 | } 5 | -------------------------------------------------------------------------------- /Chapter08/flat/message_generated.h: -------------------------------------------------------------------------------- 1 | // automatically generated by the FlatBuffers compiler, do not modify 2 | 3 | 4 | #ifndef FLATBUFFERS_GENERATED_MESSAGE_H_ 5 | #define FLATBUFFERS_GENERATED_MESSAGE_H_ 6 | 7 | #include "flatbuffers/flatbuffers.h" 8 | 9 | struct Message; 10 | 11 | FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Message FLATBUFFERS_FINAL_CLASS { 12 | private: 13 | int32_t x_; 14 | int32_t y_; 15 | 16 | public: 17 | Message() { 18 | memset(static_cast(this), 0, sizeof(Message)); 19 | } 20 | Message(int32_t _x, int32_t _y) 21 | : x_(flatbuffers::EndianScalar(_x)), 22 | y_(flatbuffers::EndianScalar(_y)) { 23 | } 24 | int32_t x() const { 25 | return flatbuffers::EndianScalar(x_); 26 | } 27 | int32_t y() const { 28 | return flatbuffers::EndianScalar(y_); 29 | } 30 | }; 31 | FLATBUFFERS_STRUCT_END(Message, 8); 32 | 33 | #endif // FLATBUFFERS_GENERATED_MESSAGE_H_ 34 | -------------------------------------------------------------------------------- /Chapter08/ipc1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(ipc1) 3 | add_executable(ipc1 ipc1.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter08/ipc1/ipc1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | std::string kSharedFile = "/tmp/test.bin"; 9 | 10 | template 11 | class Writer { 12 | private: 13 | std::ofstream out; 14 | public: 15 | Writer(std::string& name): 16 | out(name, std::ofstream::binary) {} 17 | 18 | void Write(const T& data) { 19 | out.write(reinterpret_cast(&data), sizeof(T)); 20 | } 21 | }; 22 | 23 | template 24 | class Reader { 25 | private: 26 | std::ifstream in; 27 | public: 28 | Reader(std::string& name) { 29 | for(int count=10; count && !in.is_open(); count--) { 30 | in.open(name, std::ifstream::binary); 31 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 32 | } 33 | } 34 | 35 | T Read() { 36 | int count = 10; 37 | for (;count && in.eof(); count--) { 38 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 39 | } 40 | 41 | T data; 42 | in.read(reinterpret_cast(&data), sizeof(data)); 43 | if (!in) { 44 | throw std::runtime_error("Failed to read a message"); 45 | } 46 | return data; 47 | } 48 | }; 49 | 50 | struct Message { 51 | int x, y; 52 | }; 53 | 54 | std::ostream& operator<<(std::ostream& o, const Message& m) { 55 | o << "(x=" << m.x << ", y=" << m.y << ")"; 56 | } 57 | 58 | void DoWrites() { 59 | std::vector messages {{1, 0}, {0, 1}, {1, 1}, {0, 0}}; 60 | Writer writer(kSharedFile); 61 | for (const auto& m : messages) { 62 | std::cout << "Write " << m << std::endl; 63 | writer.Write(m); 64 | } 65 | } 66 | 67 | void DoReads() { 68 | Reader reader(kSharedFile); 69 | try { 70 | while(true) { 71 | std::cout << "Read " << reader.Read() << std::endl; 72 | } 73 | } catch (const std::runtime_error& e) { 74 | std::cout << e.what() << std::endl; 75 | } 76 | } 77 | 78 | 79 | int main(int argc, char** argv) { 80 | if (fork()) { 81 | DoWrites(); 82 | } else { 83 | DoReads(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Chapter08/ipc2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(ipc2) 3 | add_executable(ipc2 ipc2.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter08/ipc2/ipc1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Embedded-Programming-with-Modern-CPP-Cookbook/4e83ae7fabac9330613bfe807afd3d9bef35c69e/Chapter08/ipc2/ipc1 -------------------------------------------------------------------------------- /Chapter08/ipc2/ipc2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | std::string kSharedFile = "/tmp/test.fifo"; 11 | 12 | template 13 | class Writer { 14 | private: 15 | std::ofstream out; 16 | public: 17 | Writer(std::string& name): 18 | out(name, std::ofstream::binary) {} 19 | 20 | void Write(const T& data) { 21 | out.write(reinterpret_cast(&data), sizeof(T)); 22 | out.flush(); 23 | } 24 | }; 25 | 26 | template 27 | class Reader { 28 | private: 29 | std::ifstream in; 30 | public: 31 | Reader(std::string& name): 32 | in(name, std::ofstream::binary) {} 33 | 34 | T Read() { 35 | T data; 36 | in.read(reinterpret_cast(&data), sizeof(data)); 37 | if (!in) { 38 | throw std::runtime_error("Failed to read a message"); 39 | } 40 | return data; 41 | } 42 | }; 43 | 44 | struct Message { 45 | int x, y; 46 | }; 47 | 48 | std::ostream& operator<<(std::ostream& o, const Message& m) { 49 | o << "(x=" << m.x << ", y=" << m.y << ")"; 50 | } 51 | 52 | void DoWrites() { 53 | std::vector messages {{1, 0}, {0, 1}, {1, 1}, {0, 0}}; 54 | Writer writer(kSharedFile); 55 | for (const auto& m : messages) { 56 | std::cout << "Write " << m << std::endl; 57 | writer.Write(m); 58 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 59 | } 60 | } 61 | 62 | void DoReads() { 63 | Reader reader(kSharedFile); 64 | try { 65 | while(true) { 66 | std::cout << "Read " << reader.Read() << std::endl; 67 | } 68 | } catch (const std::runtime_error& e) { 69 | std::cout << e.what() << std::endl; 70 | } 71 | } 72 | 73 | 74 | int main(int argc, char** argv) { 75 | int ret = mkfifo(kSharedFile.c_str(), 0600); 76 | if (!ret) { 77 | throw std::runtime_error("Failed to create named pipe"); 78 | } 79 | if (fork()) { 80 | DoWrites(); 81 | } else { 82 | DoReads(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Chapter08/ipc3/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(ipc3) 3 | add_executable(ipc3 ipc3.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | target_link_libraries(ipc3 rt) 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter08/ipc3/ipc3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | std::string kQueueName = "/test2"; 13 | 14 | class MessageQueue { 15 | private: 16 | mqd_t handle; 17 | public: 18 | MessageQueue(const std::string& name, int flags) { 19 | handle = mq_open(name.c_str(), flags); 20 | if (handle < 0) { 21 | throw std::runtime_error("Failed to open a queue for writing"); 22 | } 23 | } 24 | 25 | MessageQueue(const std::string& name, int flags, int max_count, int max_size) { 26 | struct mq_attr attrs = { 0, max_count, max_size, 0 }; 27 | handle = mq_open(name.c_str(), flags | O_CREAT, 0666, &attrs); 28 | if (handle < 0) { 29 | throw std::runtime_error("Failed to create a queue"); 30 | } 31 | } 32 | 33 | ~MessageQueue() { 34 | mq_close(handle); 35 | } 36 | 37 | void Send(const char* data, size_t len) { 38 | if (mq_send(handle, data, len, 0) < 0) { 39 | throw std::runtime_error("Failed to send a message"); 40 | } 41 | } 42 | 43 | void Receive(char* data, size_t len) { 44 | if (mq_receive(handle, data, len, 0) < len) { 45 | throw std::runtime_error("Failed to receive a message"); 46 | } 47 | } 48 | }; 49 | 50 | template 51 | class Writer { 52 | private: 53 | MessageQueue queue; 54 | public: 55 | Writer(std::string& name): 56 | queue(name, O_WRONLY) {} 57 | 58 | void Write(const T& data) { 59 | queue.Send(reinterpret_cast(&data), sizeof(data)); 60 | } 61 | }; 62 | 63 | template 64 | class Reader { 65 | private: 66 | MessageQueue queue; 67 | public: 68 | Reader(std::string& name): 69 | queue(name, O_RDONLY) {} 70 | 71 | void Run() { 72 | T data; 73 | while(true) { 74 | queue.Receive(reinterpret_cast(&data), sizeof(data)); 75 | Callback(data); 76 | } 77 | } 78 | 79 | protected: 80 | virtual void Callback(const T& data) = 0; 81 | }; 82 | 83 | struct Message { 84 | int x, y; 85 | }; 86 | 87 | std::ostream& operator<<(std::ostream& o, const Message& m) { 88 | o << "(x=" << m.x << ", y=" << m.y << ")"; 89 | } 90 | 91 | class CoordLogger : public Reader { 92 | using Reader::Reader; 93 | 94 | protected: 95 | void Callback(const Message& data) override { 96 | std::cout << "Received coordinate " << data << std::endl; 97 | } 98 | }; 99 | 100 | void DoWrites() { 101 | std::vector messages {{1, 0}, {0, 1}, {1, 1}, {0, 0}}; 102 | Writer writer(kQueueName); 103 | for (const auto& m : messages) { 104 | std::cout << "Write " << m << std::endl; 105 | writer.Write(m); 106 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 107 | } 108 | } 109 | 110 | void DoReads() { 111 | CoordLogger logger(kQueueName); 112 | logger.Run(); 113 | } 114 | 115 | 116 | int main(int argc, char** argv) { 117 | MessageQueue q(kQueueName, O_WRONLY, 10, sizeof(Message)); 118 | pid_t pid = fork(); 119 | if (pid) { 120 | DoWrites(); 121 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 122 | kill(pid, SIGTERM); 123 | } else { 124 | DoReads(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Chapter08/ipc4/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(ipc4) 3 | add_executable(ipc4 ipc4.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | target_link_libraries(ipc4 rt) 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter08/ipc4/ipc4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | std::string kQueueName = "/test2"; 13 | 14 | class MessageQueue { 15 | private: 16 | mqd_t handle; 17 | public: 18 | MessageQueue(const std::string& name, int flags) { 19 | handle = mq_open(name.c_str(), flags); 20 | if (handle < 0) { 21 | throw std::runtime_error("Failed to open a queue for writing"); 22 | } 23 | } 24 | 25 | MessageQueue(const std::string& name, int flags, int max_count, int max_size) { 26 | struct mq_attr attrs = { 0, max_count, max_size, 0 }; 27 | handle = mq_open(name.c_str(), flags | O_CREAT, 0666, &attrs); 28 | if (handle < 0) { 29 | throw std::runtime_error("Failed to create a queue"); 30 | } 31 | } 32 | 33 | ~MessageQueue() { 34 | mq_close(handle); 35 | } 36 | 37 | void Send(const char* data, size_t len) { 38 | if (mq_send(handle, data, len, 0) < 0) { 39 | throw std::runtime_error("Failed to send a message"); 40 | } 41 | } 42 | 43 | void Receive(char* data, size_t len) { 44 | if (mq_receive(handle, data, len, 0) < len) { 45 | throw std::runtime_error("Failed to receive a message"); 46 | } 47 | } 48 | }; 49 | 50 | template 51 | class Writer { 52 | private: 53 | MessageQueue queue; 54 | public: 55 | Writer(std::string& name): 56 | queue(name, O_WRONLY) {} 57 | 58 | void Write(const T& data) { 59 | queue.Send(reinterpret_cast(&data), sizeof(data)); 60 | } 61 | }; 62 | 63 | template 64 | class Reader { 65 | private: 66 | MessageQueue queue; 67 | void (*func)(const T&); 68 | public: 69 | Reader(std::string& name, void (*func)(const T&)): 70 | queue(name, O_RDONLY), func(func) {} 71 | 72 | void Run() { 73 | T data; 74 | while(true) { 75 | queue.Receive(reinterpret_cast(&data), sizeof(data)); 76 | func(data); 77 | } 78 | } 79 | }; 80 | 81 | struct Message { 82 | int x, y; 83 | }; 84 | 85 | std::ostream& operator<<(std::ostream& o, const Message& m) { 86 | o << "(x=" << m.x << ", y=" << m.y << ")"; 87 | } 88 | 89 | void DoWrites() { 90 | std::vector messages {{1, 0}, {0, 1}, {1, 1}, {0, 0}}; 91 | Writer writer(kQueueName); 92 | for (const auto& m : messages) { 93 | std::cout << "Write " << m << std::endl; 94 | writer.Write(m); 95 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 96 | } 97 | } 98 | 99 | void DoReads() { 100 | Reader logger(kQueueName, [](const Message& data) { 101 | std::cout << "Received coordinate " << data << std::endl; 102 | }); 103 | logger.Run(); 104 | } 105 | 106 | 107 | int main(int argc, char** argv) { 108 | MessageQueue q(kQueueName, O_WRONLY, 10, sizeof(Message)); 109 | pid_t pid = fork(); 110 | if (pid) { 111 | DoWrites(); 112 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 113 | kill(pid, SIGTERM); 114 | } else { 115 | DoReads(); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Chapter08/stream/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(stream) 3 | add_executable(stream stream.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter08/stream/stream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Point { 6 | int x, y; 7 | }; 8 | 9 | struct Paths { 10 | Point source; 11 | std::list destinations; 12 | }; 13 | 14 | std::ostream& operator<<(std::ostream& o, const Point& p) { 15 | o << p.x << " " << p.y << " "; 16 | return o; 17 | } 18 | 19 | std::istream& operator>>(std::istream& is, Point& p) { 20 | is >> p.x; 21 | is >> p.y; 22 | return is; 23 | } 24 | 25 | std::ostream& operator<<(std::ostream& o, const Paths& paths) { 26 | o << paths.source << paths.destinations.size() << " "; 27 | for (const auto& x : paths.destinations) { 28 | o << x; 29 | } 30 | return o; 31 | } 32 | 33 | std::istream& operator>>(std::istream& is, Paths& paths) { 34 | size_t size; 35 | is >> paths.source; 36 | is >> size; 37 | for (;size;size--) { 38 | Point tmp; 39 | is >> tmp; 40 | paths.destinations.push_back(tmp); 41 | } 42 | return is; 43 | } 44 | 45 | 46 | int main(int argc, char** argv) { 47 | Paths paths = {{0, 0}, {{1, 1}, {0, 1}, {1, 0}}}; 48 | 49 | std::stringstream in; 50 | in << paths; 51 | std::string serialized = in.str(); 52 | std::cout << "Serialized paths into the string: [" 53 | << serialized << "]" << std::endl; 54 | 55 | std::stringstream out(serialized); 56 | Paths paths2; 57 | out >> paths2; 58 | std::cout << "Original: " << paths.destinations.size() 59 | << " destinations" << std::endl; 60 | std::cout << "Restored: " << paths2.destinations.size() 61 | << " destinations" << std::endl; 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /Chapter09/gpio/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(gpio) 3 | add_executable(gpio gpio.cpp) 4 | target_link_libraries(gpio wiringPi) 5 | 6 | -------------------------------------------------------------------------------- /Chapter09/gpio/gpio.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | using namespace std::literals::chrono_literals; 8 | 9 | const int kLedPin = 0; 10 | 11 | int main (void) 12 | { 13 | 14 | if (wiringPiSetup () <0) { 15 | throw std::runtime_error("Failed to initialize wiringPi"); 16 | } 17 | 18 | pinMode (kLedPin, OUTPUT); 19 | 20 | while (true) { 21 | digitalWrite (kLedPin, HIGH); 22 | std::cout << "LED on" << std::endl; 23 | std::this_thread::sleep_for(500ms) ; 24 | digitalWrite (kLedPin, LOW); 25 | std::cout << "LED off" << std::endl; 26 | std::this_thread::sleep_for(500ms) ; 27 | } 28 | return 0 ; 29 | } 30 | -------------------------------------------------------------------------------- /Chapter09/gpiod/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(gpiod) 3 | add_executable(gpiod gpiod.cpp) 4 | target_link_libraries(gpiod gpiodcxx) 5 | 6 | -------------------------------------------------------------------------------- /Chapter09/gpiod/gpiod.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | using namespace std::literals::chrono_literals; 9 | 10 | const int kLedPin = 17; 11 | 12 | int main (void) 13 | { 14 | 15 | gpiod::chip chip("gpiochip0"); 16 | auto line = chip.get_line(kLedPin); 17 | line.request({"test", gpiod::line_request::DIRECTION_OUTPUT, 0}, 0); 18 | 19 | while (true) { 20 | line.set_value(1); 21 | std::cout << "ON" << std::endl; 22 | std::this_thread::sleep_for(500ms); 23 | line.set_value(0); 24 | std::cout << "OFF" << std::endl; 25 | std::this_thread::sleep_for(500ms); 26 | } 27 | 28 | return 0 ; 29 | } 30 | -------------------------------------------------------------------------------- /Chapter09/i2c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(i2c) 3 | add_executable(i2c i2c.cpp) 4 | 5 | -------------------------------------------------------------------------------- /Chapter09/i2c/i2c.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std::literals::chrono_literals; 11 | 12 | enum class Function : uint8_t { 13 | clear = 0x01, 14 | home = 0x02, 15 | entry_mode_set = 0x04, 16 | display_control = 0x08, 17 | cursor_shift = 0x10, 18 | fn_set = 0x20, 19 | set_ddram_addr = 0x80 20 | }; 21 | 22 | constexpr int En = 0b00000100; 23 | constexpr int Rs = 0b00000001; 24 | 25 | constexpr int kDisplayOn = 0x04; 26 | constexpr int kEntryLeft = 0x02; 27 | constexpr int kTwoLine = 0x08; 28 | constexpr int kBacklightOn = 0x08; 29 | 30 | class Lcd { 31 | int fd; 32 | 33 | public: 34 | Lcd(const char* device, int address) { 35 | fd = open(device, O_RDWR); 36 | if (fd < 0) { 37 | throw std::system_error(errno, 38 | std::system_category(), 39 | "Failed to open RTC device"); 40 | } 41 | if (ioctl(fd, I2C_SLAVE, address) < 0) { 42 | close(fd); 43 | throw std::system_error(errno, 44 | std::system_category(), 45 | "Failed to aquire bus address"); 46 | } 47 | Init(); 48 | } 49 | 50 | ~Lcd() { 51 | close(fd); 52 | } 53 | 54 | void Clear() { 55 | Call(Function::clear); 56 | std::this_thread::sleep_for(2000us); 57 | } 58 | 59 | void Display(const std::string& text, bool second=false) { 60 | Call(Function::set_ddram_addr, second ? 0x40 : 0); 61 | for(char c : text) { 62 | Write(c, Rs); 63 | } 64 | } 65 | 66 | private: 67 | 68 | void SendToI2C(uint8_t byte) { 69 | if (write(fd, &byte, 1) != 1) { 70 | throw std::system_error(errno, 71 | std::system_category(), 72 | "Write to i2c device failed"); 73 | } 74 | } 75 | 76 | void SendToLcd(uint8_t value) { 77 | value |= kBacklightOn; 78 | SendToI2C(value); 79 | SendToI2C(value | En); 80 | std::this_thread::sleep_for(1us); 81 | SendToI2C(value & ~En); 82 | std::this_thread::sleep_for(50us); 83 | } 84 | 85 | void Write(uint8_t value, uint8_t mode=0) { 86 | SendToLcd((value & 0xF0) | mode); 87 | SendToLcd((value << 4) | mode); 88 | } 89 | 90 | void Init() { 91 | // Switch to 4-bit mode 92 | for (int i = 0; i < 3; i++) { 93 | SendToLcd(0x30); 94 | std::this_thread::sleep_for(4500us); 95 | } 96 | SendToLcd(0x20); 97 | 98 | // Set display to two-line, 4 bit, 5x8 character mode 99 | Call(Function::fn_set, kTwoLine); 100 | Call(Function::display_control, kDisplayOn); 101 | Clear(); 102 | Call(Function::entry_mode_set, kEntryLeft); 103 | Home(); 104 | } 105 | 106 | void Call(Function function, uint8_t value=0) { 107 | Write((uint8_t)function | value); 108 | } 109 | 110 | void Home() { 111 | Call(Function::home); 112 | std::this_thread::sleep_for(2000us); 113 | } 114 | }; 115 | 116 | int main (int argc, char* argv[]) 117 | { 118 | Lcd lcd("/dev/i2c-1", 0x27); 119 | if (argc > 1) { 120 | lcd.Display(argv[1]); 121 | if (argc > 2) { 122 | lcd.Display(argv[2], true); 123 | } 124 | } 125 | 126 | return 0 ; 127 | } 128 | -------------------------------------------------------------------------------- /Chapter09/pwm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(pwm) 3 | add_executable(pwm pwm.cpp) 4 | target_link_libraries(pwm wiringPi) 5 | 6 | -------------------------------------------------------------------------------- /Chapter09/pwm/pwm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | using namespace std::literals::chrono_literals; 7 | 8 | const int kLedPin = 0; 9 | 10 | void Blink(std::chrono::microseconds duration, int percent_on) { 11 | digitalWrite (kLedPin, HIGH); 12 | std::this_thread::sleep_for(duration * percent_on / 100) ; 13 | digitalWrite (kLedPin, LOW); 14 | std::this_thread::sleep_for(duration * (100 - percent_on) / 100) ; 15 | } 16 | 17 | int main (void) 18 | { 19 | 20 | if (wiringPiSetup () <0) { 21 | throw std::runtime_error("Failed to initialize wiringPi"); 22 | } 23 | 24 | pinMode (kLedPin, OUTPUT); 25 | 26 | int count = 0; 27 | int delta = 1; 28 | while (true) { 29 | Blink(10ms, count); 30 | count = count + delta; 31 | if (count == 101) { 32 | delta = -1; 33 | } else if (count == 0) { 34 | delta = 1; 35 | } 36 | } 37 | return 0 ; 38 | } 39 | -------------------------------------------------------------------------------- /Chapter09/rtc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(rtc) 3 | add_executable(rtc rtc.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 9 | -------------------------------------------------------------------------------- /Chapter09/rtc/rtc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | class Rtc { 12 | int fd; 13 | public: 14 | Rtc() { 15 | fd = open("/dev/rtc", O_RDWR); 16 | if (fd < 0) { 17 | throw std::system_error(errno, 18 | std::system_category(), 19 | "Failed to open RTC device"); 20 | } 21 | } 22 | 23 | ~Rtc() { 24 | close(fd); 25 | } 26 | 27 | time_t GetTime(void) { 28 | union { 29 | struct rtc_time rtc; 30 | struct tm tm; 31 | } tm; 32 | int ret = ioctl(fd, RTC_RD_TIME, &tm.rtc); 33 | if (ret < 0) { 34 | throw std::system_error(errno, 35 | std::system_category(), 36 | "ioctl failed"); 37 | } 38 | return mktime(&tm.tm); 39 | } 40 | }; 41 | 42 | int main (void) 43 | { 44 | Rtc rtc; 45 | time_t t = rtc.GetTime(); 46 | std::cout << "Current time is " << ctime(&t) << std::endl; 47 | 48 | return 0 ; 49 | } 50 | -------------------------------------------------------------------------------- /Chapter10/udev/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(udev) 3 | add_executable(usb udev.cpp) 4 | target_link_libraries(usb udev) 5 | 6 | -------------------------------------------------------------------------------- /Chapter10/udev/udev.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | namespace usb { 8 | 9 | class Device { 10 | struct udev_device *dev; 11 | 12 | public: 13 | Device() = delete; 14 | Device(struct udev_device* dev) : dev(dev) {} 15 | 16 | Device(const Device& other) : dev(other.dev) { 17 | udev_device_ref(dev); 18 | } 19 | 20 | ~Device() { 21 | udev_device_unref(dev); 22 | } 23 | 24 | std::string action() const { return udev_device_get_action(dev); } 25 | 26 | std::string attr(const char* name) const { 27 | const char* val = udev_device_get_sysattr_value(dev, name); 28 | return val ? val : ""; 29 | } 30 | }; 31 | 32 | class Monitor { 33 | struct udev_monitor *mon; 34 | 35 | public: 36 | Monitor() { 37 | struct udev* udev = udev_new(); 38 | mon = udev_monitor_new_from_netlink(udev, "udev"); 39 | udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", NULL); 40 | udev_monitor_enable_receiving(mon); 41 | } 42 | 43 | Monitor(const Monitor& other) = delete; 44 | 45 | ~Monitor() { 46 | udev_monitor_unref(mon); 47 | } 48 | 49 | Device wait(std::function process) { 50 | struct pollfd fds[1]; 51 | fds[0].events = POLLIN; 52 | fds[0].fd = udev_monitor_get_fd(mon); 53 | 54 | while (true) { 55 | int ret = poll(fds, 1, -1); 56 | if (ret < 0) { 57 | throw std::system_error(errno, std::system_category(), 58 | "Poll failed"); 59 | } 60 | if (ret) { 61 | Device d(udev_monitor_receive_device(mon)); 62 | if (process(d)) { 63 | return d; 64 | }; 65 | } 66 | } 67 | } 68 | }; 69 | }; 70 | 71 | int main() { 72 | usb::Monitor mon; 73 | usb::Device d = mon.wait([](auto& d) { 74 | auto id = d.attr("idVendor") + ":" + d.attr("idProduct"); 75 | auto produce = d.attr("product"); 76 | std::cout << "Check [" << id << "] action: " << d.action() << std::endl; 77 | return d.action() == "bind" && id == "8086:0808"; 78 | }); 79 | std::cout << d.attr("product") << " connected, uses up to " 80 | << d.attr("bMaxPower") << std::endl; 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /Chapter11/chrono/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(chrono) 3 | add_executable(chrono chrono.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++14") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | 11 | -------------------------------------------------------------------------------- /Chapter11/chrono/chrono.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std::chrono_literals; 5 | 6 | int main() { 7 | auto a = std::chrono::system_clock::now(); 8 | auto b = a + 1s; 9 | auto c = a + 200ms; 10 | 11 | std::cout << "a < b ? " << (a < b ? "yes" : "no") << std::endl; 12 | std::cout << "a < c ? " << (a < c ? "yes" : "no") << std::endl; 13 | std::cout << "b < c ? " << (b < c ? "yes" : "no") << std::endl; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter11/delays/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(delays) 3 | add_executable(delays delays.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++14") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter11/delays/delays.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std::chrono_literals; 6 | 7 | void sleep_for(int count, auto delay) { 8 | for (int i = 0; i < count; i++) { 9 | auto start = std::chrono::system_clock::now(); 10 | std::this_thread::sleep_for(delay); 11 | auto end = std::chrono::system_clock::now(); 12 | std::chrono::duration delta = end - start; 13 | std::cout << "Sleep for: " << delta.count() << std::endl; 14 | } 15 | } 16 | 17 | void sleep_until(int count, std::chrono::milliseconds delay) { 18 | auto wake_up = std::chrono::system_clock::now(); 19 | for (int i = 0; i < 10; i++) { 20 | wake_up += delay; 21 | auto start = std::chrono::system_clock::now(); 22 | std::this_thread::sleep_until(wake_up); 23 | auto end = std::chrono::system_clock::now(); 24 | std::chrono::duration delta = end - start; 25 | std::cout << "Sleep until: " << delta.count() << std::endl; 26 | } 27 | } 28 | 29 | int main() { 30 | sleep_for(10, 100ms); 31 | sleep_until(10, 100ms); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /Chapter11/interval/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(interval) 3 | add_executable(interval interval.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter11/interval/interval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::chrono::duration prev; 6 | for (int i = 0; i < 10; i++) { 7 | auto start = std::chrono::steady_clock::now(); 8 | std::cout << i << ": "; 9 | auto end = std::chrono::steady_clock::now(); 10 | std::chrono::duration delta = end - start; 11 | std::cout << "output duration is " << delta.count() <<" us"; 12 | if (i) { 13 | auto diff = (delta - prev).count(); 14 | if (diff >= 0) { 15 | std::cout << ", " << diff << " us slower"; 16 | } else { 17 | std::cout << ", " << -diff << " us faster"; 18 | } 19 | } 20 | std::cout << std::endl; 21 | prev = delta; 22 | } 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /Chapter11/monotonic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(monotonic) 3 | add_executable(monotonic monotonic.cpp) 4 | target_link_libraries(monotonic pthread) 5 | 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | set(CMAKE_SYSTEM_PROCESSOR arm) 8 | 9 | SET(CMAKE_CXX_FLAGS "--std=c++11") 10 | 11 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 12 | 13 | -------------------------------------------------------------------------------- /Chapter11/monotonic/monotonic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | auto touched = std::chrono::steady_clock::now(); 8 | std::mutex m; 9 | std::atomic_bool ready{ false }; 10 | 11 | void Worker() { 12 | for (int i = 0; i < 10; i++) { 13 | std::this_thread::sleep_for(std::chrono::milliseconds(100 + (i % 4) * 10)); 14 | std::cout << "Step " << i << std::endl; 15 | { 16 | std::lock_guard l(m); 17 | touched = std::chrono::steady_clock::now(); 18 | } 19 | } 20 | ready = true; 21 | } 22 | 23 | 24 | int main() { 25 | std::thread t(Worker); 26 | std::chrono::milliseconds threshold(120); 27 | while(!ready) { 28 | auto now = std::chrono::steady_clock::now(); 29 | std::chrono::milliseconds delta; 30 | { 31 | std::lock_guard l(m); 32 | auto delta = now - touched; 33 | if (delta > threshold) { 34 | std::cout << "Executiuon threshold exceeded" << std::endl; 35 | } 36 | } 37 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 38 | 39 | } 40 | t.join(); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /Chapter11/timestamps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(timestamps) 3 | add_executable(timestamps timestamps.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter11/timestamps/timestamps.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | auto now = std::chrono::system_clock::now(); 6 | 7 | std::time_t ts = std::chrono::system_clock::to_time_t(now); 8 | std::cout << "POSIX timestamp: " << ts << std::endl; 9 | 10 | auto restored = std::chrono::system_clock::from_time_t(ts); 11 | 12 | std::chrono::duration delta = now - restored; 13 | std::cout << "Recovered time delta " << delta.count() << std::endl; 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter12/catch/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(catch) 3 | add_executable(catch catch.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter12/catch/catch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Error { 4 | int code; 5 | 6 | public: 7 | Error(int code): code(code) { 8 | std::cout << " Error instance " << code << " was created" << std::endl; 9 | } 10 | Error(const Error& other): code(other.code) { 11 | std::cout << " Error instance " << code << " was cloned" << std::endl; 12 | } 13 | ~Error() { 14 | std::cout << " Error instance " << code << " was destroyed" << std::endl; 15 | } 16 | }; 17 | 18 | void CatchByValue() { 19 | std::cout << "Catch by value" << std::endl; 20 | try { 21 | throw Error(1); 22 | } 23 | catch (Error e) { 24 | std::cout << " Error caught" << std::endl; 25 | } 26 | } 27 | 28 | void CatchByPointer() { 29 | std::cout << "Catch by pointer" << std::endl; 30 | try { 31 | throw new Error(2); 32 | } 33 | catch (Error* e) { 34 | std::cout << " Error caught" << std::endl; 35 | } 36 | } 37 | 38 | void CatchByReference() { 39 | std::cout << "Catch by reference" << std::endl; 40 | try { 41 | throw Error(3); 42 | } 43 | catch (const Error& e) { 44 | std::cout << " Error caught" << std::endl; 45 | } 46 | } 47 | 48 | 49 | int main() { 50 | CatchByValue(); 51 | CatchByPointer(); 52 | CatchByReference(); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /Chapter12/debounce/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(debounce) 3 | add_executable(debounce debounce.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++14") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter12/debounce/debounce.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std::chrono_literals; 6 | 7 | bool debounce(std::chrono::milliseconds timeout, bool (*handler)(void)) { 8 | bool prev = handler(); 9 | auto ts = std::chrono::steady_clock::now(); 10 | while (true) { 11 | std::this_thread::sleep_for(1ms); 12 | bool value = handler(); 13 | auto now = std::chrono::steady_clock::now(); 14 | if (value == prev) { 15 | if (now - ts > timeout) { 16 | break; 17 | } 18 | } else { 19 | prev = value; 20 | ts = now; 21 | } 22 | } 23 | return prev; 24 | } 25 | 26 | 27 | int main() { 28 | bool result = debounce(10ms, []() { 29 | return true; 30 | }); 31 | std::cout << "Result: " << result << std::endl; 32 | } 33 | -------------------------------------------------------------------------------- /Chapter12/errcode/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(errcode) 3 | add_executable(errcode errcode.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | 11 | -------------------------------------------------------------------------------- /Chapter12/errcode/errcode.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int Receive(int input, std::string& output) { 4 | if (input < 0) { 5 | return -1; 6 | } 7 | 8 | output = "Hello"; 9 | return 0; 10 | } 11 | 12 | std::string Receive(int input, int& error) { 13 | if (input < 0) { 14 | error = -1; 15 | return ""; 16 | } 17 | error = 0; 18 | return "Hello"; 19 | } 20 | 21 | std::pair Receive(int input) { 22 | std::pair result; 23 | if (input < 0) { 24 | result.first = -1; 25 | } else { 26 | result.second = "Hello"; 27 | } 28 | return result; 29 | } 30 | 31 | void Display(const char* prefix, int err, const std::string& result) { 32 | if (err < 0) { 33 | std::cout << prefix << " error: " << err << std::endl; 34 | } else { 35 | std::cout << prefix << " result: " << result << std::endl; 36 | } 37 | } 38 | 39 | void Test(int input) { 40 | std::string outputResult; 41 | int err = Receive(input, outputResult); 42 | Display(" Receive 1", err, outputResult); 43 | 44 | int outputErr = -1; 45 | std::string result = Receive(input, outputErr); 46 | Display(" Receive 2", outputErr, result); 47 | 48 | std::pair ret = Receive(input); 49 | Display(" Receive 3", ret.first, ret.second); 50 | } 51 | 52 | 53 | int main() { 54 | std::cout << "Input: -1" << std::endl; 55 | Test(-1); 56 | std::cout << "Input: 1" << std::endl; 57 | Test(1); 58 | 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /Chapter12/except/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(except) 3 | add_executable(except except.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | 11 | -------------------------------------------------------------------------------- /Chapter12/except/except.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | class Device { 7 | int fd; 8 | 9 | public: 10 | Device(const std::string& deviceName) { 11 | fd = open(deviceName.c_str(), O_RDWR); 12 | if (fd < 0) { 13 | throw std::system_error(errno, std::system_category(), 14 | "Failed to open device file"); 15 | } 16 | } 17 | 18 | ~Device() { 19 | close(fd); 20 | } 21 | 22 | void Send(const std::string& data) { 23 | size_t offset = 0; 24 | size_t len = data.size(); 25 | while (offset < data.size() - 1) { 26 | int sent = write(fd, data.data() + offset, data.size() - offset); 27 | if (sent < 0) { 28 | throw std::system_error(errno, std::system_category(), 29 | "Failed to send data"); 30 | } 31 | offset += sent; 32 | } 33 | } 34 | }; 35 | 36 | int main() { 37 | try { 38 | Device serial("/dev/ttyUSB0"); 39 | serial.Send("Hello"); 40 | } catch (std::system_error& e) { 41 | std::cout << "Error: " << e.what() << std::endl; 42 | std::cout << "Code: " << e.code() << " means \"" << e.code().message() 43 | << "\"" << std::endl; 44 | } 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /Chapter12/heartbeat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(heartbeat) 3 | add_executable(heartbeat heartbeat.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++14") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter12/heartbeat/heartbeat.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std::chrono_literals; 11 | 12 | enum class Health : uint8_t { 13 | Ok, 14 | Unhealthy, 15 | ShutDown 16 | }; 17 | 18 | class Heartbeat { 19 | int channel[2]; 20 | std::chrono::milliseconds delay; 21 | 22 | public: 23 | Heartbeat(std::chrono::milliseconds delay): 24 | delay(delay) { 25 | int rv = pipe(channel); 26 | if (rv < 0) { 27 | throw std::system_error(errno, std::system_category(), 28 | "Failed to open pipe"); 29 | } 30 | } 31 | 32 | void Report(Health status) { 33 | int rv = write(channel[1], &status, sizeof(status)); 34 | if (rv < 0) { 35 | throw std::system_error(errno, std::system_category(), 36 | "Failed to report health status"); 37 | } 38 | } 39 | 40 | bool Monitor() { 41 | struct pollfd fds[1]; 42 | fds[0].fd = channel[0]; 43 | fds[0].events = POLLIN; 44 | bool takeover = true; 45 | bool polling = true; 46 | while(polling) { 47 | fds[0].revents = 0; 48 | int rv = poll(fds, 1, delay.count()); 49 | if (rv) { 50 | if (fds[0].revents & (POLLERR | POLLHUP)) { 51 | std::cout << "Polling error occured" << std::endl; 52 | takeover = false; 53 | polling = false; 54 | break; 55 | } 56 | 57 | Health status; 58 | int count = read(fds[0].fd, &status, sizeof(status)); 59 | if (count < sizeof(status)) { 60 | std::cout << "Failed to read heartbeat data" << std::endl; 61 | break; 62 | } 63 | switch(status) { 64 | case Health::Ok: 65 | std::cout << "Active process is healthy" << std::endl; 66 | break; 67 | case Health::ShutDown: 68 | std::cout << "Shut down signalled" << std::endl; 69 | takeover = false; 70 | polling = false; 71 | break; 72 | default: 73 | std::cout << "Unhealthy status reported" << std::endl; 74 | polling = false; 75 | break; 76 | } 77 | } else if (!rv) { 78 | std::cout << "Timeout" << std::endl; 79 | polling = false; 80 | } else { 81 | if (errno != EINTR) { 82 | std::cout << "Error reading heartbeat data, retrying" << std::endl; 83 | } 84 | } 85 | } 86 | return takeover; 87 | } 88 | }; 89 | 90 | void Worker(Heartbeat& hb) { 91 | for (int i = 0; i < 5; i++) { 92 | hb.Report(Health::Ok); 93 | std::cout << "Processing" << std::endl; 94 | std::this_thread::sleep_for(100ms); 95 | } 96 | hb.Report(Health::Unhealthy); 97 | } 98 | 99 | int main() { 100 | Heartbeat hb(200ms); 101 | if (fork()) { 102 | if (hb.Monitor()) { 103 | std::cout << "Taking over" << std::endl; 104 | Worker(hb); 105 | } 106 | } else { 107 | Worker(hb); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Chapter12/static/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(static) 3 | add_executable(static static.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | 11 | -------------------------------------------------------------------------------- /Chapter12/static/static.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Complex { 5 | char* ptr; 6 | 7 | public: 8 | Complex(size_t size) noexcept { 9 | try { 10 | ptr = new(std::nothrow) char[size]; 11 | if (ptr) { 12 | std::cout << "Successfully allocated " 13 | << size << " bytes" << std::endl; 14 | } else { 15 | std::cout << "Failed to allocate " 16 | << size << " bytes" << std::endl; 17 | } 18 | } catch (...) { 19 | // Do nothing 20 | } 21 | } 22 | 23 | ~Complex() { 24 | try { 25 | if (ptr) { 26 | delete[] ptr; 27 | std::cout << "Deallocated memory" << std::endl; 28 | } else { 29 | std::cout << "Memory was not allocated" << std::endl; 30 | } 31 | } catch (...) { 32 | // Do nothing 33 | } 34 | } 35 | 36 | bool IsValid() const { return nullptr != ptr; } 37 | }; 38 | 39 | Complex small(100); 40 | Complex large(SIZE_MAX); 41 | 42 | int main() { 43 | std::cout << "Small object is " << (small.IsValid()? "valid" : "invalid") 44 | << std::endl; 45 | std::cout << "Large object is " << (large.IsValid()? "valid" : "invalid") 46 | << std::endl; 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /Chapter12/watchdog/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(watchdog) 3 | add_executable(watchdog watchdog.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++14") 9 | 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 11 | 12 | -------------------------------------------------------------------------------- /Chapter12/watchdog/watchdog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | using namespace std::chrono_literals; 8 | 9 | class Watchdog { 10 | std::chrono::seconds seconds; 11 | 12 | public: 13 | Watchdog(std::chrono::seconds seconds): 14 | seconds(seconds) { 15 | feed(); 16 | } 17 | 18 | ~Watchdog() { 19 | alarm(0); 20 | } 21 | 22 | void feed() { 23 | alarm(seconds.count()); 24 | } 25 | }; 26 | 27 | int main() { 28 | Watchdog watchdog(2s); 29 | std::chrono::milliseconds delay = 700ms; 30 | for (int i = 0; i < 10; i++) { 31 | watchdog.feed(); 32 | std::cout << delay.count() << "ms delay" << std::endl; 33 | std::this_thread::sleep_for(delay); 34 | delay += 300ms; 35 | } 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /Chapter13/array/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(array) 3 | add_executable(array array.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++17") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | -------------------------------------------------------------------------------- /Chapter13/array/array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using DataFrame = std::array; 7 | 8 | void GenerateData(DataFrame& frame) { 9 | std::random_device rd; 10 | std::generate(frame.begin(), frame.end(), 11 | [&rd]() { return rd() % 100; }); 12 | } 13 | 14 | void ProcessData(const DataFrame& frame) { 15 | std::cout << "Processing array of " 16 | << frame.size() << " elements: ["; 17 | for (auto x : frame) { 18 | std::cout << x << " "; 19 | } 20 | auto mm = std::minmax_element(frame.begin(), frame.end()); 21 | std::cout << "] min: " << *mm.first 22 | << ", max: " << *mm.second << std::endl; 23 | } 24 | 25 | int main() { 26 | DataFrame data; 27 | 28 | for (int i = 0; i < 4; i++) { 29 | GenerateData(data); 30 | ProcessData(data); 31 | } 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /Chapter13/expected/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(expected) 3 | add_executable(expected expected.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++17") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | -------------------------------------------------------------------------------- /Chapter13/expected/expected.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | template 9 | class Expected { 10 | std::variant v; 11 | 12 | public: 13 | Expected(T val) : v(val) {} 14 | Expected(std::error_code e) : v(e) {} 15 | 16 | bool valid() const { 17 | return std::holds_alternative(v); 18 | } 19 | 20 | const T& value() const { 21 | return std::get(v); 22 | } 23 | 24 | const std::error_code& error() const { 25 | return std::get(v); 26 | } 27 | }; 28 | 29 | Expected OpenForRead(const std::string& name) { 30 | int fd = ::open(name.c_str(), O_RDONLY); 31 | if (fd < 0) { 32 | return Expected(std::error_code(errno, std::system_category())); 33 | } 34 | return Expected(fd); 35 | } 36 | 37 | int main() { 38 | auto result = OpenForRead("nonexistent.txt"); 39 | if (result.valid()) { 40 | std::cout << "File descriptor" << result.value() << std::endl; 41 | } else { 42 | std::cout << "Open failed: " << result.error().message() << std::endl; 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /Chapter13/pinthreads/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(pinthreads) 3 | add_executable(pinthreads pinthreads.cpp) 4 | target_link_libraries(pinthreads pthread) 5 | 6 | SET(CMAKE_CXX_FLAGS "--std=c++14") 7 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 8 | 9 | -------------------------------------------------------------------------------- /Chapter13/pinthreads/pinthreads.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | using namespace std::chrono_literals; 9 | 10 | bool PinToCore(std::thread& t, int core) { 11 | cpu_set_t cpuset; 12 | CPU_ZERO(&cpuset); 13 | CPU_SET(core, &cpuset); 14 | int errCode = pthread_setaffinity_np(t.native_handle(), 15 | sizeof(cpuset), &cpuset); 16 | if (errCode < 0) { 17 | std::cerr << "Failed to set CPU affinity:" 18 | << errCode << std::endl; 19 | return false; 20 | } 21 | return true; 22 | } 23 | 24 | void Worker(int n) { 25 | while(true) { 26 | std::clog << "Worker " << n << " running on CPU " 27 | << sched_getcpu() << std::endl; 28 | std::this_thread::sleep_for(1s); 29 | } 30 | } 31 | 32 | int main() { 33 | int n = std::thread::hardware_concurrency(); 34 | std::clog << n << " cores detected" << std::endl; 35 | //PinToCore(std::this_thread, 0); 36 | for (int i = 1; i < n; i++) { 37 | std::clog << "Create worker thread for CPU " << i << std::endl; 38 | std::thread t = std::thread(Worker, i); 39 | PinToCore(t, i); 40 | t.detach(); 41 | } 42 | std::cout << "Main thread on core " << sched_getcpu() << std::endl; 43 | for (int i = 0; i < 4; i++) { 44 | std::clog << "Main thread on cpu " << sched_getcpu() << std::endl; 45 | std::this_thread::sleep_for(1s); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Chapter13/realtime/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(realtime) 3 | add_executable(realtime realtime.cpp) 4 | target_link_libraries(realtime pthread) 5 | 6 | SET(CMAKE_CXX_FLAGS "--std=c++14") 7 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabihf-g++) 8 | 9 | -------------------------------------------------------------------------------- /Chapter13/realtime/realtime.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | using namespace std::chrono_literals; 9 | 10 | void ConfigureRealtime(pthread_t thread_id, int priority) { 11 | sched_param sch; 12 | sch.sched_priority = 20; 13 | if (pthread_setschedparam(thread_id, SCHED_FIFO, &sch)) { 14 | throw std::system_error(errno, std::system_category(), 15 | "Failed to set real-time priority"); 16 | } 17 | } 18 | 19 | void Measure(const char* text) { 20 | struct timespec prev; 21 | timespec_get(&prev, TIME_UTC); 22 | struct timespec delay{0, 10}; 23 | for (int i = 0; i < 100000; i++) { 24 | nanosleep(&delay, nullptr); 25 | } 26 | struct timespec ts; 27 | timespec_get(&ts, TIME_UTC); 28 | double delta = (ts.tv_sec - prev.tv_sec) + (double)(ts.tv_nsec - prev.tv_nsec) / 1000000000; 29 | std::clog << text << " completed in " << delta << " sec" << std::endl; 30 | } 31 | 32 | void RealTimeThread(const char* txt) { 33 | ConfigureRealtime(pthread_self(), 1); 34 | Measure(txt); 35 | } 36 | 37 | int main() { 38 | std::thread t1(RealTimeThread, "Real-time"); 39 | std::thread t2(Measure, "Normal"); 40 | t1.join(); 41 | t2.join(); 42 | } 43 | -------------------------------------------------------------------------------- /Chapter14/assert/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(assert) 3 | add_executable(assert assert.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++11") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | -------------------------------------------------------------------------------- /Chapter14/assert/assert.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class TimeSaver1 { 9 | int fd = -1; 10 | 11 | public: 12 | TimeSaver1(const char* name) { 13 | assert(name != nullptr); 14 | assert(name[0] != '\0'); 15 | 16 | int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0600); 17 | if (fd < 0) { 18 | throw std::system_error(errno, std::system_category(), 19 | "Failed to open file"); 20 | } 21 | assert(this->fd >= 0); 22 | } 23 | 24 | ~TimeSaver1() { 25 | assert(this->fd >= 0); 26 | close(fd); 27 | } 28 | }; 29 | 30 | int main() { 31 | TimeSaver1 ts1(""); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /Chapter14/returns/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(returns) 3 | add_executable(returns returns.cpp) 4 | 5 | set(CMAKE_SYSTEM_NAME Linux) 6 | set(CMAKE_SYSTEM_PROCESSOR arm) 7 | 8 | SET(CMAKE_CXX_FLAGS "--std=c++17") 9 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++) 10 | -------------------------------------------------------------------------------- /Chapter14/returns/returns.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | [[nodiscard]] ssize_t Write(int fd, const void* buffer, ssize_t size) { 8 | return ::write(fd, buffer, size); 9 | } 10 | 11 | class TimeSaver1 { 12 | int fd; 13 | 14 | public: 15 | TimeSaver1(const char* name) { 16 | int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0600); 17 | if (fd < 0) { 18 | throw std::system_error(errno, std::system_category(), 19 | "Failed to open file"); 20 | } 21 | Update(); 22 | } 23 | 24 | ~TimeSaver1() { 25 | Update(); 26 | close(fd); 27 | } 28 | 29 | 30 | private: 31 | void Update() { 32 | time_t tm; 33 | time(&tm); 34 | Write(fd, &tm, sizeof(tm)); 35 | } 36 | }; 37 | 38 | class TimeSaver2 { 39 | int fd; 40 | 41 | public: 42 | TimeSaver2(const char* name) { 43 | fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0600); 44 | if (fd < 0) { 45 | throw std::system_error(errno, std::system_category(), 46 | "Failed to open file"); 47 | } 48 | Update(); 49 | } 50 | 51 | ~TimeSaver2() { 52 | Update(); 53 | if (close(fd) < 0) { 54 | throw std::system_error(errno, std::system_category(), 55 | "Failed to close file"); 56 | } 57 | } 58 | 59 | private: 60 | void Update() { 61 | time_t tm = time(&tm); 62 | int rv = Write(fd, &tm, sizeof(tm)); 63 | if (rv < 0) { 64 | throw std::system_error(errno, std::system_category(), 65 | "Failed to write to file"); 66 | } 67 | } 68 | }; 69 | 70 | int main() { 71 | TimeSaver1 ts1("timestamp1.bin"); 72 | TimeSaver2 ts2("timestamp2.bin"); 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /Chapter15/snippet.cpp: -------------------------------------------------------------------------------- 1 | void setup() { 2 | pinMode(LED_BUILTIN, OUTPUT); 3 | Serial.begin(9600); 4 | while (!Serial); 5 | } 6 | 7 | void loop() { 8 | if (Serial.available() > 0) { 9 | int inByte = Serial.read(); 10 | if (inByte == '1') { 11 | Serial.print("Turn LED on\n"); 12 | digitalWrite(LED_BUILTIN, HIGH); 13 | } else if (inByte == '0') { 14 | Serial.print("Turn LED off\n"); 15 | digitalWrite(LED_BUILTIN, LOW); 16 | } else { 17 | Serial.print("Ignore byte "); 18 | Serial.print(inByte); 19 | Serial.print("\n"); 20 | } 21 | delay(500); 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Embedded Programming with Modern C++ Cookbook 5 | Embedded Programming with Modern C++ Cookbook by Packt Publishing 6 | 7 | ## Erratas 8 | 9 | On page 62 "Create a file called CMakeLists.txt in the loop subdirectory" should read 10 | "Create a file called CMakeLists.txt in the fixed_types subdirectory". 11 | 12 | On page 65 "Create a file called CMakeLists.txt in the loop subdirectory" should read 13 | "Create a file called CMakeLists.txt in the sizet subdirectory". 14 | 15 | On page 67 "Use your favorite text editor to create a file called loop.cpp in the loop subdirectory" should read 16 | "Use your favorite text editor to create a file called endianness.cpp in the endianness subdirectory". 17 | 18 | On page 68 "Create a file called CMakeLists.txt in the loop subdirectory" should read 19 | "Create a file called CMakeLists.txt in the endianness subdirectory". 20 | 21 | On page 72 "Create a file called CMakeLists.txt in the loop subdirectory" should read 22 | "Create a file called CMakeLists.txt in the enconv subdirectory". 23 | 24 | On page 75 "Use your favorite text editor to create a file called alignment.cpp in the loop subdirectory" should read 25 | "Use your favorite text editor to create a file called alignment.cpp in the alignment subdirectory.". 26 | 27 | On page 76 "Create a file called CMakeLists.txt in the loop subdirectory" should read 28 | "Create a file called CMakeLists.txt in the alignment subdirectory". 29 | 30 | On page 82 "Create a file called CMakeLists.txt in the loop subdirectory" should read 31 | "Create a file called CMakeLists.txt in the cache_align subdirectory". 32 | 33 | On page 139 "Create a file called CMakeLists.txt in the loop subdirectory" should read 34 | "Create a file called CMakeLists.txt in the prealloc subdirectory". 35 | 36 | On page 142 "Create a file called CMakeLists.txt in the loop subdirectory" should read 37 | "Create a file called CMakeLists.txt in the objpool subdirectory". 38 | 39 | On page 149 "Create a file called CMakeLists.txt in the loop subdirectory" should read 40 | "Create a file called CMakeLists.txt in the ringbuf subdirectory". 41 | 42 | On page 156 "Create a file called CMakeLists.txt in the loop subdirectory" should read 43 | "Create a file called CMakeLists.txt in the shmem subdirectory". 44 | 45 | On page 167 "Create a file called CMakeLists.txt in the loop subdirectory" should read 46 | "Create a file called CMakeLists.txt in the threads subdirectory". 47 | 48 | On page 170 "Create a file called CMakeLists.txt in the loop subdirectory" should read 49 | "Create a file called CMakeLists.txt in the mutex subdirectory". 50 | 51 | On page 174 "Create a file called CMakeLists.txt in the loop subdirectory" should read 52 | "Create a file called CMakeLists.txt in the condvar subdirectory". 53 | 54 | On page 179 "Create a file called CMakeLists.txt in the loop subdirectory" should read 55 | "Create a file called CMakeLists.txt in the atomic subdirectory". 56 | 57 | On page 183 "Create a file called CMakeLists.txt in the loop subdirectory" should read 58 | "Create a file called CMakeLists.txt in the memorder subdirectory". 59 | 60 | On page 187 "Create a file called CMakeLists.txt in the loop subdirectory" should read 61 | "Create a file called CMakeLists.txt in the lockfree subdirectory". 62 | 63 | On page 192 "Create a file called CMakeLists.txt in the loop subdirectory" should read 64 | "Create a file called CMakeLists.txt in the shmatomic subdirectory". 65 | 66 | On page 197 "Create a file called CMakeLists.txt in the loop subdirectory" should read 67 | "Create a file called CMakeLists.txt in the async subdirectory". 68 | ### Download a free PDF 69 | 70 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
71 |

https://packt.link/free-ebook/9781838821043

--------------------------------------------------------------------------------