Renaming all folders
This commit is contained in:
45
04_AdvancedFileIO/README.md
Normal file
45
04_AdvancedFileIO/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Chapter 4 – Advanced File I/O
|
||||
|
||||
## Scatter/Gather I/O
|
||||
- Scatter/gather I/O allows reading or writing data to/from multiple buffers in a single system call.
|
||||
- Uses `readv()` and `writev()`:
|
||||
- `readv(fd, iov, iovcnt)`: reads into multiple buffers (`iov` array).
|
||||
- `writev(fd, iov, iovcnt)`: writes from multiple buffers.
|
||||
- Improves efficiency by reducing system calls.
|
||||
|
||||
## Event Poll (`select()`, `poll()`, `epoll`)
|
||||
- Traditional multiplexing: `select()`, `poll()` (limited scalability).
|
||||
- Linux-specific: `epoll` for efficient event notification.
|
||||
- `epoll_create()`: create epoll instance.
|
||||
- `epoll_ctl()`: control interest list (add, modify, remove fds).
|
||||
- `epoll_wait()`: wait for events.
|
||||
- Edge-triggered vs level-triggered modes.
|
||||
|
||||
## Memory-Mapped Files (`mmap()`)
|
||||
- Maps files or devices into memory for direct access.
|
||||
- System calls: `mmap()`, `munmap()`.
|
||||
- Benefits: faster I/O, shared memory.
|
||||
- Use `msync()` to synchronize changes.
|
||||
- Resizing mappings, changing protections.
|
||||
- Advisory calls:
|
||||
- `posix_fadvise()`: give advice about expected I/O patterns.
|
||||
- `readahead()`: prefetch file data.
|
||||
- Pros and cons of memory mapping.
|
||||
|
||||
## Asynchronous I/O and I/O Scheduling
|
||||
- Distinction between synchronous and asynchronous I/O.
|
||||
- Linux AIO APIs for asynchronous operations.
|
||||
- I/O schedulers:
|
||||
- Manage disk request ordering.
|
||||
- Examples: CFQ, noop, deadline.
|
||||
- Optimizing I/O performance by choosing schedulers.
|
||||
- Concepts of disk addressing and request life cycle.
|
||||
|
||||
## Miscellaneous
|
||||
- `ioctl()`: device-specific operations.
|
||||
- Zero-copy transfers: `sendfile()`, `splice()`.
|
||||
|
||||
---
|
||||
|
||||
> This chapter covers advanced Linux I/O techniques aimed at improving performance and flexibility in system programming.
|
||||
|
||||
98
04_AdvancedFileIO/blocks.c
Normal file
98
04_AdvancedFileIO/blocks.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* Copyright (c) 2025 Fabio Scotto di Santolo
|
||||
*/
|
||||
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/fs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* get_block - for the file associated with the given fd, returns
|
||||
* the physical block mapping to logical_block
|
||||
*/
|
||||
int get_block(int fd, int logical_block);
|
||||
|
||||
/* get_nr_blocks - returns the number of logical blocks
|
||||
* consumed by the file associated with fd
|
||||
*/
|
||||
int get_nr_blocks(int fd);
|
||||
|
||||
/* print_blocks - for each logical block consumed by the file
|
||||
* associated with fd, prints to standard out the tuple
|
||||
* "(logical block, physical block)"
|
||||
*/
|
||||
void print_blocks(int fd);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: %s <file>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd = open(argv[1], O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_blocks(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_block(int fd, int logical_block)
|
||||
{
|
||||
int ret = ioctl(fd, FIBMAP, &logical_block);
|
||||
if (ret < 0) {
|
||||
perror("ioctl");
|
||||
return -1;
|
||||
}
|
||||
return logical_block;
|
||||
}
|
||||
|
||||
int get_nr_blocks(int fd)
|
||||
{
|
||||
struct stat buf;
|
||||
int ret = fstat(fd, &buf);
|
||||
if (ret < 0) {
|
||||
perror("fstat");
|
||||
return -1;
|
||||
}
|
||||
return buf.st_blocks;
|
||||
}
|
||||
|
||||
void print_blocks(int fd)
|
||||
{
|
||||
int nr_blocks = get_nr_blocks(fd);
|
||||
if (nr_blocks < 0) {
|
||||
fprintf(stderr, "get_nr_blocks failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nr_blocks == 0) {
|
||||
printf("no allocated blocks\n");
|
||||
return;
|
||||
} else if (nr_blocks == 1) {
|
||||
printf("1 block\n");
|
||||
} else {
|
||||
printf("%d blocks\n\n", nr_blocks);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nr_blocks; i++) {
|
||||
int phys_block = get_block(fd, i);
|
||||
if (phys_block < 0) {
|
||||
fprintf(stderr, "get_block failed!\n");
|
||||
return;
|
||||
}
|
||||
if (!phys_block)
|
||||
continue;
|
||||
|
||||
printf("(%u, %u) ", i, phys_block);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
BIN
04_AdvancedFileIO/buccaneer.txt
Normal file
BIN
04_AdvancedFileIO/buccaneer.txt
Normal file
Binary file not shown.
47
04_AdvancedFileIO/inode.c
Normal file
47
04_AdvancedFileIO/inode.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* Copyright (c) 2025 Fabio Scotto di Santolo
|
||||
*/
|
||||
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* get_inode - returns the inode of the file associated
|
||||
* with the given file descriptor, or -1 on failure.
|
||||
*/
|
||||
int get_inode(int fd);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: %s <file>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd = open(argv[1], O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int inode = get_inode(fd);
|
||||
printf("%d\n", inode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_inode(int fd)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
int ret = fstat(fd, &buf);
|
||||
if (ret < 0) {
|
||||
perror("fstat");
|
||||
return -1;
|
||||
}
|
||||
return buf.st_ino;
|
||||
}
|
||||
60
04_AdvancedFileIO/mmap.c
Normal file
60
04_AdvancedFileIO/mmap.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* Copyright (c) 2025 Fabio Scotto di Santolo
|
||||
*/
|
||||
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: %s <file>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd = open(argv[1], O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct stat sb;
|
||||
if (fstat(fd, &sb) == -1) {
|
||||
perror("fstat");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
fprintf(stderr, "%s is not a file\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *p = (char *)mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (p == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (close(fd) == -1) {
|
||||
perror("close");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int len = 0; len < sb.st_size; len++) {
|
||||
putchar(p[len]);
|
||||
}
|
||||
|
||||
if (munmap(p, sb.st_size) == -1) {
|
||||
perror("munmap");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
48
04_AdvancedFileIO/readv.c
Normal file
48
04_AdvancedFileIO/readv.c
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* Copyright (c) 2025 Fabio Scotto di Santolo
|
||||
*/
|
||||
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char foo[48], bar[51], baz[49];
|
||||
int fd = open("buccaneer.txt", O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// setup our iovec structures
|
||||
struct iovec iov[3];
|
||||
iov[0].iov_base = foo;
|
||||
iov[0].iov_len = sizeof(foo);
|
||||
iov[1].iov_base = bar;
|
||||
iov[1].iov_len = sizeof(bar);
|
||||
iov[2].iov_base = baz;
|
||||
iov[2].iov_len = sizeof(baz);
|
||||
|
||||
// read into the structures with a single call
|
||||
int nr = readv(fd, iov, 3);
|
||||
if (nr == -1) {
|
||||
perror("readv");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
printf("%d: %s", i, (char *)iov[i].iov_base);
|
||||
|
||||
if (close(fd)) {
|
||||
perror("close");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
50
04_AdvancedFileIO/writev.c
Normal file
50
04_AdvancedFileIO/writev.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* Copyright (c) 2025 Fabio Scotto di Santolo
|
||||
*/
|
||||
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct iovec iov[3];
|
||||
|
||||
char *buf[] = {"The term buccaneer comes from the word boucan.\n",
|
||||
"A boucan is a wooden frame used for cooking meet.\n",
|
||||
"Buccaneer is the West Indies name for a pirate.\n"};
|
||||
|
||||
int fd = open("buccaneer.txt", O_WRONLY | O_CREAT | O_TRUNC);
|
||||
if (fd == -1) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// fill out three iovec structures
|
||||
for (int i = 0; i < 3; i++) {
|
||||
iov[i].iov_base = buf[i];
|
||||
iov[i].iov_len = strlen(buf[i]) + 1;
|
||||
}
|
||||
|
||||
// with a single call, write them all out
|
||||
ssize_t nr = writev(fd, iov, 3);
|
||||
if (nr == -1) {
|
||||
perror("writev");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("wrote %lu bytes\n", nr);
|
||||
|
||||
if (close(fd)) {
|
||||
perror("close");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user