Format code automatically for regression tests

This commit is contained in:
Ruihan Li
2024-03-16 00:15:19 +08:00
committed by Tate, Hongliang Tian
parent 60cd65d837
commit 82de200d03
22 changed files with 1344 additions and 1123 deletions

View File

@ -157,6 +157,7 @@ docs: $(CARGO_OSDK)
.PHONY: format .PHONY: format
format: format:
@./tools/format_all.sh @./tools/format_all.sh
@make --no-print-directory -C regression format
.PHONY: check .PHONY: check
check: $(CARGO_OSDK) check: $(CARGO_OSDK)
@ -175,6 +176,7 @@ check: $(CARGO_OSDK)
@for dir in $(OSDK_CRATES); do \ @for dir in $(OSDK_CRATES); do \
(cd $$dir && cargo osdk clippy -- -- -D warnings) || exit 1; \ (cd $$dir && cargo osdk clippy -- -- -D warnings) || exit 1; \
done done
@make --no-print-directory -C regression check
.PHONY: clean .PHONY: clean
clean: clean:

View File

@ -120,6 +120,14 @@ $(EXT2_IMAGE):
.PHONY: build .PHONY: build
build: $(INITRAMFS_IMAGE) $(EXT2_IMAGE) build: $(INITRAMFS_IMAGE) $(EXT2_IMAGE)
.PHONY: format
format:
@make --no-print-directory -C apps format
.PHONY: check
check:
@make --no-print-directory -C apps check
.PHONY: clean .PHONY: clean
clean: clean:
@rm -rf $(BUILD_DIR) @rm -rf $(BUILD_DIR)

View File

@ -0,0 +1,125 @@
# SPDX-License-Identifier: GPL-2.0
#
# This file was copied from Linux kernel, or more precisely, from:
#
# https://github.com/torvalds/linux/blob/e5eb28f6d1afebed4bb7d740a797d0390bd3a357/.clang-format
#
# We have removed the long but useless `ForEachMacros` option.
# clang-format configuration file. Intended for clang-format >= 11.
#
# For more information, see:
#
# Documentation/process/clang-format.rst
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: 8
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
# Taken from git's rules
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatementsExceptForEachMacros
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
...

View File

@ -1,12 +1,17 @@
# SPDX-License-Identifier: MPL-2.0 # SPDX-License-Identifier: MPL-2.0
MAKEFLAGS += --no-builtin-rules # Prevent the implicit rules from compiling ".c" or ".s" files automatically. MAKEFLAGS += --no-builtin-rules # Prevent the implicit rules from compiling ".c" or ".s" files automatically.
MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
CUR_DIR := $(patsubst %/,%,$(dir $(MKFILE_PATH))) CUR_DIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
INITRAMFS ?= $(CUR_DIR)/../build/initramfs INITRAMFS ?= $(CUR_DIR)/../build/initramfs
REGRESSION_BUILD_DIR ?= $(INITRAMFS)/regression REGRESSION_BUILD_DIR ?= $(INITRAMFS)/regression
TEST_APPS := signal_c pthread network hello_world hello_pie hello_c fork_c fork execve pty TEST_APPS := signal_c pthread network hello_world hello_pie hello_c fork_c fork execve pty
C_SOURCES := $(shell find . -type f \( -name "*.c" -or -name "*.h" \) )
.PHONY: all .PHONY: all
all: $(TEST_APPS) scripts all: $(TEST_APPS) scripts
@ -14,6 +19,16 @@ all: $(TEST_APPS) scripts
$(TEST_APPS): $(TEST_APPS):
@make --no-print-directory -C $@ @make --no-print-directory -C $@
.PHONY: format
format:
@echo "Fixing code format for regression tests..."
@clang-format -i $(C_SOURCES)
.PHONY: check
check:
@echo "Checking code format for regression tests..."
@clang-format --dry-run --Werror $(C_SOURCES)
$(REGRESSION_BUILD_DIR): $(REGRESSION_BUILD_DIR):
@mkdir -p $@ @mkdir -p $@

View File

@ -3,15 +3,16 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
int main() { int main()
char* argv[] = { "argv1", "argv2", NULL }; {
char* envp[] = { "home=/", "version=1.1", NULL }; char *argv[] = { "argv1", "argv2", NULL };
// The hello will be put at /execve/hello in InitRamfs char *envp[] = { "home=/", "version=1.1", NULL };
printf("Execve a new file /execve/hello:\n"); // The hello will be put at /execve/hello in InitRamfs
// flush the stdout content to ensure the content print to console printf("Execve a new file /execve/hello:\n");
fflush(stdout); // flush the stdout content to ensure the content print to console
execve("/regression/execve/hello", argv, envp); fflush(stdout);
printf("Should not print\n"); execve("/regression/execve/hello", argv, envp);
fflush(stdout); printf("Should not print\n");
return 0; fflush(stdout);
return 0;
} }

View File

@ -2,17 +2,18 @@
#include <stdio.h> #include <stdio.h>
int main(int argc, char *argv[], char *envp[]) { int main(int argc, char *argv[], char *envp[])
printf("Hello world from hello.c(execved in execve.c)!\n"); {
printf("argc = %d\n", argc); printf("Hello world from hello.c(execved in execve.c)!\n");
for(int i = 0; i < argc; i++) { printf("argc = %d\n", argc);
printf("%s\n", argv[i]); for (int i = 0; i < argc; i++) {
} printf("%s\n", argv[i]);
for(int i = 0 ;; i++) { }
if (envp[i] == NULL) { for (int i = 0;; i++) {
break; if (envp[i] == NULL) {
} break;
printf("%s\n", envp[i]); }
} printf("%s\n", envp[i]);
return 0; }
return 0;
} }

View File

@ -3,14 +3,15 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
int main() { int main()
printf("before fork\n"); {
fflush(stdout); printf("before fork\n");
if(fork() == 0) { fflush(stdout);
printf("after fork: Hello from child\n"); if (fork() == 0) {
} else { printf("after fork: Hello from child\n");
printf("after fork: Hello from parent\n"); } else {
} printf("after fork: Hello from parent\n");
fflush(stdout); }
return 0; fflush(stdout);
return 0;
} }

View File

@ -2,7 +2,8 @@
#include <stdio.h> #include <stdio.h>
int main() { int main()
printf("hello world from hello_c!\n"); {
return 0; printf("hello world from hello_c!\n");
return 0;
} }

View File

@ -2,7 +2,8 @@
#include <stdio.h> #include <stdio.h>
int main() { int main()
printf("hello world from hello_pie!\n"); {
return 0; printf("hello world from hello_pie!\n");
return 0;
} }

View File

@ -8,135 +8,135 @@
static int new_bound_socket(struct sockaddr_in *addr) static int new_bound_socket(struct sockaddr_in *addr)
{ {
int sockfd; int sockfd;
sockfd = socket(PF_INET, SOCK_STREAM, 0); sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd < 0) { if (sockfd < 0) {
perror("new_bound_socket: socket"); perror("new_bound_socket: socket");
return -1; return -1;
} }
if (bind(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) { if (bind(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
perror("new_bound_socket: bind"); perror("new_bound_socket: bind");
close(sockfd); close(sockfd);
return -1; return -1;
} }
return sockfd; return sockfd;
} }
static int new_connected_socket(struct sockaddr_in *addr) static int new_connected_socket(struct sockaddr_in *addr)
{ {
int sockfd; int sockfd;
sockfd = socket(PF_INET, SOCK_STREAM, 0); sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd < 0) { if (sockfd < 0) {
perror("new_connected_socket: socket"); perror("new_connected_socket: socket");
return -1; return -1;
} }
if (connect(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) { if (connect(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
perror("new_connected_socket: connect"); perror("new_connected_socket: connect");
close(sockfd); close(sockfd);
return -1; return -1;
} }
return sockfd; return sockfd;
} }
#define MAX_TEST_BACKLOG 5 #define MAX_TEST_BACKLOG 5
int test_listen_backlog(struct sockaddr_in *addr, int backlog) int test_listen_backlog(struct sockaddr_in *addr, int backlog)
{ {
int listenfd; int listenfd;
int connectfd[MAX_TEST_BACKLOG], acceptfd[MAX_TEST_BACKLOG]; int connectfd[MAX_TEST_BACKLOG], acceptfd[MAX_TEST_BACKLOG];
int num_connectfd = 0, num_acceptfd = 0; int num_connectfd = 0, num_acceptfd = 0;
int ret = -1; int ret = -1;
struct sockaddr caddr; struct sockaddr caddr;
socklen_t caddrlen = sizeof(caddr); socklen_t caddrlen = sizeof(caddr);
listenfd = new_bound_socket(addr); listenfd = new_bound_socket(addr);
if (listenfd < 0) { if (listenfd < 0) {
fprintf(stderr, fprintf(stderr,
"Test failed: Error occurs in new_bound_socket\n"); "Test failed: Error occurs in new_bound_socket\n");
return -1; return -1;
} }
if (listen(listenfd, backlog) < 0) { if (listen(listenfd, backlog) < 0) {
perror("listen"); perror("listen");
fprintf(stderr, "Test failed: Error occurs in listen\n"); fprintf(stderr, "Test failed: Error occurs in listen\n");
goto out; goto out;
} }
for (; num_connectfd < backlog; ++num_connectfd) { for (; num_connectfd < backlog; ++num_connectfd) {
connectfd[num_connectfd] = new_connected_socket(addr); connectfd[num_connectfd] = new_connected_socket(addr);
if (connectfd[num_connectfd] < 0) if (connectfd[num_connectfd] < 0)
break; break;
} }
if (num_connectfd != backlog) { if (num_connectfd != backlog) {
fprintf(stderr, fprintf(stderr,
"Test failed: listen(backlog=%d) allows only %d pending connections\n", "Test failed: listen(backlog=%d) allows only %d pending connections\n",
backlog, num_connectfd); backlog, num_connectfd);
goto out; goto out;
} }
fprintf(stderr, fprintf(stderr,
"Test passed: listen(backlog=%d) allows >=%d pending connections\n", "Test passed: listen(backlog=%d) allows >=%d pending connections\n",
backlog, num_connectfd); backlog, num_connectfd);
for (; num_acceptfd < num_connectfd; ++num_acceptfd) { for (; num_acceptfd < num_connectfd; ++num_acceptfd) {
acceptfd[num_acceptfd] = accept(listenfd, &caddr, &caddrlen); acceptfd[num_acceptfd] = accept(listenfd, &caddr, &caddrlen);
if (acceptfd[num_acceptfd] < 0) { if (acceptfd[num_acceptfd] < 0) {
perror("accept"); perror("accept");
break; break;
} }
} }
if (num_acceptfd != num_connectfd) { if (num_acceptfd != num_connectfd) {
fprintf(stderr, fprintf(stderr,
"Test failed: Only %d pending connections can be accept()'ed out " "Test failed: Only %d pending connections can be accept()'ed out "
"of %d\n", "of %d\n",
num_acceptfd, num_connectfd); num_acceptfd, num_connectfd);
goto out; goto out;
} }
fprintf(stderr, fprintf(stderr,
"Test passed: All of %d pending connections can be accept()'ed\n", "Test passed: All of %d pending connections can be accept()'ed\n",
num_acceptfd); num_acceptfd);
ret = 0; ret = 0;
out: out:
while (--num_acceptfd >= 0) while (--num_acceptfd >= 0)
close(acceptfd[num_acceptfd]); close(acceptfd[num_acceptfd]);
while (--num_connectfd >= 0) while (--num_connectfd >= 0)
close(connectfd[num_connectfd]); close(connectfd[num_connectfd]);
close(listenfd); close(listenfd);
return ret; return ret;
} }
int main(void) int main(void)
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
int backlog; int backlog;
int err = 0; int err = 0;
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
if (inet_aton("127.0.0.1", &addr.sin_addr) < 0) { if (inet_aton("127.0.0.1", &addr.sin_addr) < 0) {
fprintf(stderr, "inet_aton cannot parse 127.0.0.1\n"); fprintf(stderr, "inet_aton cannot parse 127.0.0.1\n");
return -1; return -1;
} }
for (backlog = 0; backlog <= MAX_TEST_BACKLOG; ++backlog) { for (backlog = 0; backlog <= MAX_TEST_BACKLOG; ++backlog) {
// Avoid "bind: Address already in use" // Avoid "bind: Address already in use"
addr.sin_port = htons(8080 + backlog); addr.sin_port = htons(8080 + backlog);
err = test_listen_backlog(&addr, backlog); err = test_listen_backlog(&addr, backlog);
if (err != 0) if (err != 0)
break; break;
} }
return err ? -1 : 0; return err ? -1 : 0;
} }

View File

@ -12,264 +12,264 @@
static int new_bound_socket(struct sockaddr_in *addr) static int new_bound_socket(struct sockaddr_in *addr)
{ {
int sockfd; int sockfd;
sockfd = socket(PF_INET, SOCK_STREAM, 0); sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd < 0) { if (sockfd < 0) {
perror("new_bound_socket: socket"); perror("new_bound_socket: socket");
return -1; return -1;
} }
if (bind(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) { if (bind(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
perror("new_bound_socket: bind"); perror("new_bound_socket: bind");
close(sockfd); close(sockfd);
return -1; return -1;
} }
return sockfd; return sockfd;
} }
static int new_connected_socket(struct sockaddr_in *addr) static int new_connected_socket(struct sockaddr_in *addr)
{ {
int sockfd; int sockfd;
sockfd = socket(PF_INET, SOCK_STREAM, 0); sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd < 0) { if (sockfd < 0) {
perror("new_connected_socket: socket"); perror("new_connected_socket: socket");
return -1; return -1;
} }
if (connect(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) { if (connect(sockfd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
perror("new_connected_socket: connect"); perror("new_connected_socket: connect");
close(sockfd); close(sockfd);
return -1; return -1;
} }
return sockfd; return sockfd;
} }
static int accept_without_addr(int sockfd) static int accept_without_addr(int sockfd)
{ {
struct sockaddr addr; struct sockaddr addr;
socklen_t addrlen = sizeof(addr); socklen_t addrlen = sizeof(addr);
int acceptfd; int acceptfd;
acceptfd = accept(sockfd, &addr, &addrlen); acceptfd = accept(sockfd, &addr, &addrlen);
if (acceptfd < 0) { if (acceptfd < 0) {
perror("accept_without_addr: accept"); perror("accept_without_addr: accept");
return -1; return -1;
} }
return acceptfd; return acceptfd;
} }
static int mark_filde_nonblock(int flide) static int mark_filde_nonblock(int flide)
{ {
int flags; int flags;
flags = fcntl(flide, F_GETFL, 0); flags = fcntl(flide, F_GETFL, 0);
if (flags < 0) { if (flags < 0) {
perror("mark_filde_nonblock: fcntl(F_GETFL)"); perror("mark_filde_nonblock: fcntl(F_GETFL)");
return -1; return -1;
} }
if (fcntl(flide, F_SETFL, flags | O_NONBLOCK) < 0) { if (fcntl(flide, F_SETFL, flags | O_NONBLOCK) < 0) {
perror("mark_filde_nonblock: fcntl(F_SETFL)"); perror("mark_filde_nonblock: fcntl(F_SETFL)");
return -1; return -1;
} }
return 0; return 0;
} }
static int mark_filde_mayblock(int flide) static int mark_filde_mayblock(int flide)
{ {
int flags; int flags;
flags = fcntl(flide, F_GETFL, 0); flags = fcntl(flide, F_GETFL, 0);
if (flags < 0) { if (flags < 0) {
perror("mark_filde_mayblock: fcntl(F_GETFL)"); perror("mark_filde_mayblock: fcntl(F_GETFL)");
return -1; return -1;
} }
if (fcntl(flide, F_SETFL, flags & ~O_NONBLOCK) < 0) { if (fcntl(flide, F_SETFL, flags & ~O_NONBLOCK) < 0) {
perror("mark_filde_mayblock: fcntl(F_SETFL)"); perror("mark_filde_mayblock: fcntl(F_SETFL)");
return -1; return -1;
} }
return 0; return 0;
} }
static char buffer[4096] = "Hello, world"; static char buffer[4096] = "Hello, world";
static ssize_t receive_all(int sockfd) static ssize_t receive_all(int sockfd)
{ {
size_t recv_len = 0; size_t recv_len = 0;
ssize_t ret; ssize_t ret;
if (mark_filde_nonblock(sockfd) < 0) { if (mark_filde_nonblock(sockfd) < 0) {
perror("receive_all: mark_filde_nonblock"); perror("receive_all: mark_filde_nonblock");
return -1; return -1;
} }
for (;;) { for (;;) {
ret = recv(sockfd, buffer, sizeof(buffer), 0); ret = recv(sockfd, buffer, sizeof(buffer), 0);
if (ret < 0 && errno == EAGAIN) if (ret < 0 && errno == EAGAIN)
break; break;
if (ret < 0) { if (ret < 0) {
perror("receive_all: recv"); perror("receive_all: recv");
return -1; return -1;
} }
recv_len += ret; recv_len += ret;
} }
return recv_len; return recv_len;
} }
int test_full_send_buffer(struct sockaddr_in *addr) int test_full_send_buffer(struct sockaddr_in *addr)
{ {
int listenfd, sendfd, recvfd; int listenfd, sendfd, recvfd;
int ret = -1, wstatus; int ret = -1, wstatus;
size_t sent_len = 0; size_t sent_len = 0;
ssize_t sent; ssize_t sent;
int pid; int pid;
listenfd = new_bound_socket(addr); listenfd = new_bound_socket(addr);
if (listenfd < 0) { if (listenfd < 0) {
fprintf(stderr, fprintf(stderr,
"Test failed: Error occurs in new_bound_socket\n"); "Test failed: Error occurs in new_bound_socket\n");
return -1; return -1;
} }
if (listen(listenfd, 2) < 0) { if (listen(listenfd, 2) < 0) {
perror("listen"); perror("listen");
fprintf(stderr, "Test failed: Error occurs in listen\n"); fprintf(stderr, "Test failed: Error occurs in listen\n");
goto out_listen; goto out_listen;
} }
sendfd = new_connected_socket(addr); sendfd = new_connected_socket(addr);
if (sendfd < 0) { if (sendfd < 0) {
fprintf(stderr, fprintf(stderr,
"Test failed: Error occurs in new_connected_socket\n"); "Test failed: Error occurs in new_connected_socket\n");
goto out_listen; goto out_listen;
} }
recvfd = accept_without_addr(listenfd); recvfd = accept_without_addr(listenfd);
if (recvfd < 0) { if (recvfd < 0) {
fprintf(stderr, fprintf(stderr,
"Test failed: Error occurs in accept_without_addr\n"); "Test failed: Error occurs in accept_without_addr\n");
goto out_send; goto out_send;
} }
if (mark_filde_nonblock(sendfd) < 0) { if (mark_filde_nonblock(sendfd) < 0) {
fprintf(stderr, fprintf(stderr,
"Test failed: Error occurs in mark_filde_nonblock\n"); "Test failed: Error occurs in mark_filde_nonblock\n");
goto out; goto out;
} }
for (;;) { for (;;) {
sent = send(sendfd, buffer, sizeof(buffer), 0); sent = send(sendfd, buffer, sizeof(buffer), 0);
if (sent < 0 && errno == EAGAIN) if (sent < 0 && errno == EAGAIN)
break; break;
if (sent < 0) { if (sent < 0) {
perror("send"); perror("send");
fprintf(stderr, "Test failed: Error occurs in send\n"); fprintf(stderr, "Test failed: Error occurs in send\n");
goto out; goto out;
} }
sent_len += sent; sent_len += sent;
} }
if (mark_filde_mayblock(sendfd) < 0) { if (mark_filde_mayblock(sendfd) < 0) {
fprintf(stderr, fprintf(stderr,
"Test failed: Error occurs in mark_filde_mayblock\n"); "Test failed: Error occurs in mark_filde_mayblock\n");
goto out; goto out;
} }
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
perror("fork"); perror("fork");
fprintf(stderr, "Test failed: Error occurs in fork\n"); fprintf(stderr, "Test failed: Error occurs in fork\n");
goto out; goto out;
} }
if (pid == 0) { if (pid == 0) {
int i; int i;
ssize_t recv_len; ssize_t recv_len;
// Ensure that the parent executes send() first, then the child // Ensure that the parent executes send() first, then the child
// executes recv(). // executes recv().
sleep(1); sleep(1);
fprintf(stderr, "Start receiving...\n"); fprintf(stderr, "Start receiving...\n");
recv_len = receive_all(recvfd); recv_len = receive_all(recvfd);
if (recv_len < 0) { if (recv_len < 0) {
fprintf(stderr, fprintf(stderr,
"Test failed: Error occurs in receive_all\n"); "Test failed: Error occurs in receive_all\n");
goto out; goto out;
} }
fprintf(stderr, "Received bytes: %lu\n", recv_len); fprintf(stderr, "Received bytes: %lu\n", recv_len);
if (recv_len != sent_len + 1) { if (recv_len != sent_len + 1) {
fprintf(stderr, fprintf(stderr,
"Test failed: Mismatched sent bytes and received bytes\n"); "Test failed: Mismatched sent bytes and received bytes\n");
goto out; goto out;
} }
ret = 0; ret = 0;
goto out; goto out;
} }
sent = send(sendfd, buffer, 1, 0); sent = send(sendfd, buffer, 1, 0);
if (sent < 0) { if (sent < 0) {
perror("send"); perror("send");
fprintf(stderr, "Test failed: Error occurs in send\n"); fprintf(stderr, "Test failed: Error occurs in send\n");
goto wait; goto wait;
} }
sent_len += 1; sent_len += 1;
fprintf(stderr, "Sent bytes: %lu\n", sent_len); fprintf(stderr, "Sent bytes: %lu\n", sent_len);
ret = 0; ret = 0;
wait: wait:
if (wait(&wstatus) < 0) { if (wait(&wstatus) < 0) {
perror("wait"); perror("wait");
fprintf(stderr, "Test failed: Error occurs in wait\n"); fprintf(stderr, "Test failed: Error occurs in wait\n");
ret = -1; ret = -1;
} else if (WEXITSTATUS(wstatus) != 0) { } else if (WEXITSTATUS(wstatus) != 0) {
fprintf(stderr, "Test failed: Error occurs in child process\n"); fprintf(stderr, "Test failed: Error occurs in child process\n");
ret = -1; ret = -1;
} }
if (ret == 0) if (ret == 0)
fprintf(stderr, fprintf(stderr,
"Test passed: Equal sent bytes and received bytes\n"); "Test passed: Equal sent bytes and received bytes\n");
out: out:
close(recvfd); close(recvfd);
out_send: out_send:
close(sendfd); close(sendfd);
out_listen: out_listen:
close(listenfd); close(listenfd);
return ret; return ret;
} }
int main(void) int main(void)
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(8080); addr.sin_port = htons(8080);
if (inet_aton("127.0.0.1", &addr.sin_addr) < 0) { if (inet_aton("127.0.0.1", &addr.sin_addr) < 0) {
fprintf(stderr, "inet_aton cannot parse 127.0.0.1\n"); fprintf(stderr, "inet_aton cannot parse 127.0.0.1\n");
return -1; return -1;
} }
return test_full_send_buffer(&addr); return test_full_send_buffer(&addr);
} }

View File

@ -8,33 +8,34 @@
#define MESG1 "Hello from child" #define MESG1 "Hello from child"
#define MESG2 "Hello from parent" #define MESG2 "Hello from parent"
int main() { int main()
int sockets[2], child; {
char buf[1024]; int sockets[2], child;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) { char buf[1024];
perror("create socket pair"); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
exit(1); perror("create socket pair");
} exit(1);
if ((child = fork()) == -1) }
perror("fork"); if ((child = fork()) == -1)
else if (child) { perror("fork");
// parent else if (child) {
close(sockets[0]); // parent
if (read(sockets[1], buf, 1024) < 0) close(sockets[0]);
perror("read from child"); if (read(sockets[1], buf, 1024) < 0)
printf("Receive from child: %s\n", buf); perror("read from child");
if (write(sockets[1], MESG2, sizeof(MESG2)) < 0) printf("Receive from child: %s\n", buf);
perror("write to child"); if (write(sockets[1], MESG2, sizeof(MESG2)) < 0)
close(sockets[1]); perror("write to child");
} else { close(sockets[1]);
// child } else {
close(sockets[1]); // child
if (write(sockets[0], MESG1, sizeof(MESG1)) < 0) close(sockets[1]);
perror("write to parent"); if (write(sockets[0], MESG1, sizeof(MESG1)) < 0)
if (read(sockets[0], buf, 1024) < 0) perror("write to parent");
perror("read from parent"); if (read(sockets[0], buf, 1024) < 0)
printf("Receive from parent: %s\n", buf); perror("read from parent");
close(sockets[0]); printf("Receive from parent: %s\n", buf);
} close(sockets[0]);
return 0; }
return 0;
} }

View File

@ -7,63 +7,73 @@
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <unistd.h> #include <unistd.h>
int main() { int main()
int sockfd; {
int option; int sockfd;
int option;
// Create tcp socket // Create tcp socket
sockfd = socket(AF_INET, SOCK_STREAM, 0); sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) { if (sockfd < 0) {
perror("Socket creation failed"); perror("Socket creation failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Get send buffer size // Get send buffer size
int sendbuf; int sendbuf;
socklen_t sendbuf_len = sizeof(sendbuf); socklen_t sendbuf_len = sizeof(sendbuf);
if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuf, &sendbuf_len) < 0 || sendbuf_len != sizeof(sendbuf)) { if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuf, &sendbuf_len) <
perror("Getting SO_SNDBUF option failed"); 0 ||
exit(EXIT_FAILURE); sendbuf_len != sizeof(sendbuf)) {
} perror("Getting SO_SNDBUF option failed");
exit(EXIT_FAILURE);
}
int error; int error;
socklen_t error_len = sizeof(error); socklen_t error_len = sizeof(error);
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &error_len ) < 0 || error_len != sizeof(error) || error != 0) { if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &error_len) < 0 ||
perror("Getting SO_SNDBUF option failed"); error_len != sizeof(error) || error != 0) {
exit(EXIT_FAILURE); perror("Getting SO_SNDBUF option failed");
} exit(EXIT_FAILURE);
}
// Disable Nagle algorithm // Disable Nagle algorithm
option = 1; option = 1;
if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option)) < 0) { if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &option,
perror("Setting TCP_NODELAY option failed"); sizeof(option)) < 0) {
exit(EXIT_FAILURE); perror("Setting TCP_NODELAY option failed");
} exit(EXIT_FAILURE);
}
// Enable reuse addr // Enable reuse addr
option = 1; option = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)) < 0) { if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option,
perror("Setting SO_REUSEADDR option failed"); sizeof(option)) < 0) {
exit(EXIT_FAILURE); perror("Setting SO_REUSEADDR option failed");
} exit(EXIT_FAILURE);
}
// Print new value
int nagle;
socklen_t nagle_len = sizeof(nagle);
if (getsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &nagle, &nagle_len) < 0 || nagle != 1) {
perror("Getting TCP_NODELAY option failed.");
exit(EXIT_FAILURE);
}
int reuseaddr; // Print new value
socklen_t reuseaddr_len = sizeof(reuseaddr); int nagle;
if (getsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, &reuseaddr_len) < 0 || reuseaddr != 1) { socklen_t nagle_len = sizeof(nagle);
perror("Getting SO_REUSEADDR option failed."); if (getsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &nagle, &nagle_len) <
exit(EXIT_FAILURE); 0 ||
} nagle != 1) {
perror("Getting TCP_NODELAY option failed.");
exit(EXIT_FAILURE);
}
// Close socket int reuseaddr;
close(sockfd); socklen_t reuseaddr_len = sizeof(reuseaddr);
if (getsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
&reuseaddr_len) < 0 ||
reuseaddr != 1) {
perror("Getting SO_REUSEADDR option failed.");
exit(EXIT_FAILURE);
}
return 0; // Close socket
close(sockfd);
return 0;
} }

View File

@ -8,37 +8,39 @@
#define PORT 8080 #define PORT 8080
int main() { int main()
int sock = 0, valread; {
struct sockaddr_in serv_addr; int sock = 0, valread;
char *hello = "Hello from client"; struct sockaddr_in serv_addr;
char buffer[1024] = {0}; char *hello = "Hello from client";
char buffer[1024] = { 0 };
// Create socket // Create socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n"); printf("\n Socket creation error \n");
return -1; return -1;
} }
serv_addr.sin_family = AF_INET; serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT); serv_addr.sin_port = htons(PORT);
// Convert IPv4 address from text to binary form // Convert IPv4 address from text to binary form
if (inet_pton(AF_INET, "127.0.0.1", &(serv_addr.sin_addr)) <= 0) { if (inet_pton(AF_INET, "127.0.0.1", &(serv_addr.sin_addr)) <= 0) {
printf("\n Invalid address/ Address not supported \n"); printf("\n Invalid address/ Address not supported \n");
return -1; return -1;
} }
// Connect to the server // Connect to the server
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) <
printf("\n Connection Failed \n"); 0) {
return -1; printf("\n Connection Failed \n");
} return -1;
}
// Send message to the server and receive the reply // Send message to the server and receive the reply
send(sock, hello, strlen(hello), 0); send(sock, hello, strlen(hello), 0);
printf("Hello message sent\n"); printf("Hello message sent\n");
valread = read(sock, buffer, 1024); valread = read(sock, buffer, 1024);
printf("Server: %s\n", buffer); printf("Server: %s\n", buffer);
return 0; return 0;
} }

View File

@ -8,58 +8,61 @@
#define PORT 8080 #define PORT 8080
int main() { int main()
int server_fd, new_socket, valread; {
struct sockaddr_in address; int server_fd, new_socket, valread;
int opt = 1; struct sockaddr_in address;
int addrlen = sizeof(address); int opt = 1;
char buffer[1024] = {0}; int addrlen = sizeof(address);
char *hello = "Hello from server"; char buffer[1024] = { 0 };
char *hello = "Hello from server";
// Create socket // Create socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed"); perror("socket failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Set socket options // Set socket options
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt,
perror("setsockopt failed"); sizeof(opt))) {
exit(EXIT_FAILURE); perror("setsockopt failed");
} exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// Convert IPv4 address from text to binary form address.sin_family = AF_INET;
if (inet_pton(AF_INET, "127.0.0.1", &(address.sin_addr)) <= 0) { address.sin_addr.s_addr = INADDR_ANY;
printf("\n Invalid address/ Address not supported \n"); address.sin_port = htons(PORT);
return -1;
}
// Bind the socket to specified IP and port // Convert IPv4 address from text to binary form
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { if (inet_pton(AF_INET, "127.0.0.1", &(address.sin_addr)) <= 0) {
perror("bind failed"); printf("\n Invalid address/ Address not supported \n");
exit(EXIT_FAILURE); return -1;
} }
// Listen for connections // Bind the socket to specified IP and port
if (listen(server_fd, 3) < 0) { if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("listen failed"); perror("bind failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Accept the connection // Listen for connections
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { if (listen(server_fd, 3) < 0) {
perror("accept failed"); perror("listen failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Read the message from the client and reply // Accept the connection
valread = read(new_socket, buffer, 1024); if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
printf("Client: %s\n", buffer); (socklen_t *)&addrlen)) < 0) {
send(new_socket, hello, strlen(hello), 0); perror("accept failed");
printf("Hello message sent\n"); exit(EXIT_FAILURE);
return 0; }
// Read the message from the client and reply
valread = read(new_socket, buffer, 1024);
printf("Client: %s\n", buffer);
send(new_socket, hello, strlen(hello), 0);
printf("Hello message sent\n");
return 0;
} }

View File

@ -12,45 +12,51 @@
#define SERVER_PORT 1234 #define SERVER_PORT 1234
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024
int main() { int main()
int sock_fd; {
char buffer[BUFFER_SIZE]; int sock_fd;
struct sockaddr_in serv_addr; char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr;
// Create UDP socket // Create UDP socket
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed"); perror("socket creation failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Set server address // Set server address
memset(&serv_addr, 0, sizeof(serv_addr)); memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET; serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERVER_PORT); serv_addr.sin_port = htons(SERVER_PORT);
if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) { if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
perror("invalid IP address"); perror("invalid IP address");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Send massage to server // Send massage to server
const char* message = "Hello world from udp client!"; const char *message = "Hello world from udp client!";
if (sendto(sock_fd, message, strlen(message), 0, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { if (sendto(sock_fd, message, strlen(message), 0,
perror("sendto failed"); (const struct sockaddr *)&serv_addr,
exit(EXIT_FAILURE); sizeof(serv_addr)) < 0) {
} perror("sendto failed");
exit(EXIT_FAILURE);
}
// Receive message from server // Receive message from server
struct sockaddr_in sender_addr; struct sockaddr_in sender_addr;
socklen_t sender_len = sizeof(sender_addr); socklen_t sender_len = sizeof(sender_addr);
int recv_len; int recv_len;
if ((recv_len = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&sender_addr, &sender_len)) < 0) { if ((recv_len = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0,
perror("recvfrom failed"); (struct sockaddr *)&sender_addr,
exit(EXIT_FAILURE); &sender_len)) < 0) {
} perror("recvfrom failed");
buffer[recv_len] = '\0'; exit(EXIT_FAILURE);
printf("Received %s from %s:%d\n", buffer, inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port)); }
buffer[recv_len] = '\0';
printf("Received %s from %s:%d\n", buffer,
inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port));
// close socket // close socket
close(sock_fd); close(sock_fd);
return 0; return 0;
} }

View File

@ -12,54 +12,59 @@
#define SERVER_PORT 1234 #define SERVER_PORT 1234
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024
int main() { int main()
int sock_fd; {
char buffer[BUFFER_SIZE]; int sock_fd;
struct sockaddr_in serv_addr; char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr;
// Create UDP socket // Create UDP socket
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed"); perror("socket creation failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Set server address // Set server address
memset(&serv_addr, 0, sizeof(serv_addr)); memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET; serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERVER_PORT); serv_addr.sin_port = htons(SERVER_PORT);
if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) { if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
perror("invalid IP address"); perror("invalid IP address");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Bind to server address // Bind to server address
if (bind(sock_fd, (struct sockaddr*)&serv_addr, if (bind(sock_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) <
sizeof(serv_addr)) 0) {
< 0) { perror("bind failed");
perror("bind failed"); exit(EXIT_FAILURE);
exit(EXIT_FAILURE); }
}
// Receive message from client // Receive message from client
struct sockaddr_in sender_addr; struct sockaddr_in sender_addr;
socklen_t sender_len = sizeof(sender_addr); socklen_t sender_len = sizeof(sender_addr);
int recv_len; int recv_len;
if ((recv_len = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&sender_addr, &sender_len)) < 0) { if ((recv_len = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0,
perror("recvfrom failed"); (struct sockaddr *)&sender_addr,
exit(EXIT_FAILURE); &sender_len)) < 0) {
} perror("recvfrom failed");
buffer[recv_len] = '\0'; exit(EXIT_FAILURE);
printf("Received %s from %s:%d\n", buffer, inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port)); }
buffer[recv_len] = '\0';
printf("Received %s from %s:%d\n", buffer,
inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port));
/// Send message to client /// Send message to client
const char* message = "Hello world from udp server!"; const char *message = "Hello world from udp server!";
if (sendto(sock_fd, message, strlen(message), 0, (const struct sockaddr *)&sender_addr, sizeof(sender_addr)) < 0) { if (sendto(sock_fd, message, strlen(message), 0,
perror("sendto failed"); (const struct sockaddr *)&sender_addr,
exit(EXIT_FAILURE); sizeof(sender_addr)) < 0) {
} perror("sendto failed");
exit(EXIT_FAILURE);
}
// 关闭socket // 关闭socket
close(sock_fd); close(sock_fd);
return 0; return 0;
} }

View File

@ -11,55 +11,58 @@
#define SOCKET_NAME "/tmp/test.sock" #define SOCKET_NAME "/tmp/test.sock"
#define BUFFER_SIZE 128 #define BUFFER_SIZE 128
int main() { int main()
int client_fd, len; {
struct sockaddr_un server_addr, peer_addr; int client_fd, len;
char buf[BUFFER_SIZE]; struct sockaddr_un server_addr, peer_addr;
char buf[BUFFER_SIZE];
// Create Client Socket // Create Client Socket
client_fd = socket(AF_UNIX, SOCK_STREAM, 0); client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (client_fd == -1) { if (client_fd == -1) {
perror("socket"); perror("socket");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Connect Server // Connect Server
memset(&server_addr, 0, sizeof(server_addr)); memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX; server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, SOCKET_NAME, sizeof(server_addr.sun_path) - 1); strncpy(server_addr.sun_path, SOCKET_NAME,
sizeof(server_addr.sun_path) - 1);
if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) { if (connect(client_fd, (struct sockaddr *)&server_addr,
perror("connect"); sizeof(server_addr)) == -1) {
exit(EXIT_FAILURE); perror("connect");
} exit(EXIT_FAILURE);
}
int addrlen = sizeof(peer_addr); int addrlen = sizeof(peer_addr);
int rc = getpeername(client_fd, (struct sockaddr *)&peer_addr, int rc =
&addrlen); getpeername(client_fd, (struct sockaddr *)&peer_addr, &addrlen);
if (rc == -1) { if (rc == -1) {
perror("getpeername"); perror("getpeername");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("server path = %s\n", peer_addr.sun_path); printf("server path = %s\n", peer_addr.sun_path);
// Read from server // Read from server
memset(buf, 0, BUFFER_SIZE); memset(buf, 0, BUFFER_SIZE);
if (read(client_fd, buf, BUFFER_SIZE) == -1) { if (read(client_fd, buf, BUFFER_SIZE) == -1) {
perror("read"); perror("read");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("Client Received: %s\n", buf);
// Send message to server printf("Client Received: %s\n", buf);
printf("Client is connected to server\n");
char* mesg = "Hello from unix socket client";
if (write(client_fd, mesg, strlen(mesg)) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
// Close socket // Send message to server
close(client_fd); printf("Client is connected to server\n");
char *mesg = "Hello from unix socket client";
if (write(client_fd, mesg, strlen(mesg)) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
return 0; // Close socket
close(client_fd);
return 0;
} }

View File

@ -11,68 +11,71 @@
#define SOCKET_NAME "/tmp/test.sock" #define SOCKET_NAME "/tmp/test.sock"
#define BUFFER_SIZE 128 #define BUFFER_SIZE 128
int main() { int main()
int server_fd, accepted_fd, len; {
struct sockaddr_un server_addr, client_addr; int server_fd, accepted_fd, len;
char buf[BUFFER_SIZE]; struct sockaddr_un server_addr, client_addr;
char buf[BUFFER_SIZE];
// 创建Server Socket // 创建Server Socket
server_fd = socket(AF_UNIX, SOCK_STREAM, 0); server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (server_fd == -1) { if (server_fd == -1) {
perror("socket"); perror("socket");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// 绑定Socket地址 // 绑定Socket地址
memset(&server_addr, 0, sizeof(server_addr)); memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX; server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, SOCKET_NAME, sizeof(server_addr.sun_path) - 1); strncpy(server_addr.sun_path, SOCKET_NAME,
sizeof(server_addr.sun_path) - 1);
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) { if (bind(server_fd, (struct sockaddr *)&server_addr,
perror("bind"); sizeof(server_addr)) == -1) {
exit(EXIT_FAILURE); perror("bind");
} exit(EXIT_FAILURE);
}
// 监听连接请求 // 监听连接请求
if (listen(server_fd, 5) == -1) { if (listen(server_fd, 5) == -1) {
perror("listen"); perror("listen");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("Server is listening...\n"); printf("Server is listening...\n");
// 接收连接请求 // 接收连接请求
len = sizeof(client_addr); len = sizeof(client_addr);
accepted_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len); accepted_fd = accept(server_fd, (struct sockaddr *)&client_addr, &len);
if (accepted_fd == -1) { if (accepted_fd == -1) {
perror("accept"); perror("accept");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
int addrlen = sizeof(client_addr); int addrlen = sizeof(client_addr);
int rc = getpeername(accepted_fd, (struct sockaddr *)&client_addr, int rc = getpeername(accepted_fd, (struct sockaddr *)&client_addr,
&addrlen); &addrlen);
if (rc == -1) { if (rc == -1) {
perror("getpeername"); perror("getpeername");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("accepted client path = %s\n", client_addr.sun_path); printf("accepted client path = %s\n", client_addr.sun_path);
printf("Server is connected to client\n"); printf("Server is connected to client\n");
char* mesg = "Hello from unix socket server"; char *mesg = "Hello from unix socket server";
write(accepted_fd, mesg, strlen(mesg)); write(accepted_fd, mesg, strlen(mesg));
// 读取客户端发送的数据并打印 // 读取客户端发送的数据并打印
memset(buf, 0, BUFFER_SIZE); memset(buf, 0, BUFFER_SIZE);
if (read(accepted_fd, buf, BUFFER_SIZE) == -1) { if (read(accepted_fd, buf, BUFFER_SIZE) == -1) {
perror("read"); perror("read");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("Server Received: %s\n", buf); printf("Server Received: %s\n", buf);
// 关闭Socket // 关闭Socket
close(accepted_fd); close(accepted_fd);
close(server_fd); close(server_fd);
unlink(SOCKET_NAME); unlink(SOCKET_NAME);
return 0; return 0;
} }

View File

@ -20,91 +20,96 @@
// Helper functions // Helper functions
// ============================================================================ // ============================================================================
#define THROW_ERROR(fmt, ...) do { \ #define THROW_ERROR(fmt, ...) \
printf("\t\tERROR:" fmt " in func %s at line %d of file %s with errno %d: %s\n", \ do { \
##__VA_ARGS__, __func__, __LINE__, __FILE__, errno, strerror(errno)); \ printf("\t\tERROR:" fmt \
return -1; \ " in func %s at line %d of file %s with errno %d: %s\n", \
} while (0) ##__VA_ARGS__, __func__, __LINE__, __FILE__, errno, \
strerror(errno)); \
return -1; \
} while (0)
// ============================================================================ // ============================================================================
// Helper macros // Helper macros
// ============================================================================ // ============================================================================
#define NTHREADS (3)
#define NTHREADS (3) #define STACK_SIZE (8 * 1024)
#define STACK_SIZE (8 * 1024)
// ============================================================================ // ============================================================================
// The test case of concurrent counter // The test case of concurrent counter
// ============================================================================ // ============================================================================
#define LOCAL_COUNT (1000UL) #define LOCAL_COUNT (1000UL)
#define EXPECTED_GLOBAL_COUNT (LOCAL_COUNT * NTHREADS) #define EXPECTED_GLOBAL_COUNT (LOCAL_COUNT * NTHREADS)
struct thread_arg { struct thread_arg {
int ti; int ti;
long local_count; long local_count;
volatile unsigned long *global_count; volatile unsigned long *global_count;
pthread_mutex_t *mutex; pthread_mutex_t *mutex;
}; };
static void *thread_func(void *_arg) { static void *thread_func(void *_arg)
struct thread_arg *arg = _arg; {
for (long i = 0; i < arg->local_count; i++) { struct thread_arg *arg = _arg;
pthread_mutex_lock(arg->mutex); for (long i = 0; i < arg->local_count; i++) {
(*arg->global_count)++; pthread_mutex_lock(arg->mutex);
pthread_mutex_unlock(arg->mutex); (*arg->global_count)++;
} pthread_mutex_unlock(arg->mutex);
return NULL; }
return NULL;
} }
static int test_mutex_with_concurrent_counter(void) { static int test_mutex_with_concurrent_counter(void)
/* {
/*
* Multiple threads are to increase a global counter concurrently * Multiple threads are to increase a global counter concurrently
*/ */
volatile unsigned long global_count = 0; volatile unsigned long global_count = 0;
pthread_t threads[NTHREADS]; pthread_t threads[NTHREADS];
struct thread_arg thread_args[NTHREADS]; struct thread_arg thread_args[NTHREADS];
/* /*
* Protect the counter with a mutex * Protect the counter with a mutex
*/ */
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL); pthread_mutex_init(&mutex, NULL);
/* /*
* Start the threads * Start the threads
*/ */
for (int ti = 0; ti < NTHREADS; ti++) { for (int ti = 0; ti < NTHREADS; ti++) {
struct thread_arg *thread_arg = &thread_args[ti]; struct thread_arg *thread_arg = &thread_args[ti];
thread_arg->ti = ti; thread_arg->ti = ti;
thread_arg->local_count = LOCAL_COUNT; thread_arg->local_count = LOCAL_COUNT;
thread_arg->global_count = &global_count; thread_arg->global_count = &global_count;
thread_arg->mutex = &mutex; thread_arg->mutex = &mutex;
if (pthread_create(&threads[ti], NULL, thread_func, thread_arg) < 0) { if (pthread_create(&threads[ti], NULL, thread_func,
printf("ERROR: pthread_create failed (ti = %d)\n", ti); thread_arg) < 0) {
return -1; printf("ERROR: pthread_create failed (ti = %d)\n", ti);
} return -1;
} }
/* }
/*
* Wait for the threads to finish * Wait for the threads to finish
*/ */
for (int ti = 0; ti < NTHREADS; ti++) { for (int ti = 0; ti < NTHREADS; ti++) {
if (pthread_join(threads[ti], NULL) < 0) { if (pthread_join(threads[ti], NULL) < 0) {
printf("ERROR: pthread_join failed (ti = %d)\n", ti); printf("ERROR: pthread_join failed (ti = %d)\n", ti);
return -1; return -1;
} }
} }
/* /*
* Check the correctness of the concurrent counter * Check the correctness of the concurrent counter
*/ */
if (global_count != EXPECTED_GLOBAL_COUNT) { if (global_count != EXPECTED_GLOBAL_COUNT) {
printf("ERROR: incorrect global_count (actual = %ld, expected = %ld)\n", printf("ERROR: incorrect global_count (actual = %ld, expected = %ld)\n",
global_count, EXPECTED_GLOBAL_COUNT); global_count, EXPECTED_GLOBAL_COUNT);
return -1; return -1;
} }
pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&mutex);
return 0; return 0;
} }
// ============================================================================ // ============================================================================
@ -112,171 +117,181 @@ static int test_mutex_with_concurrent_counter(void) {
// ============================================================================ // ============================================================================
struct thread_robust_arg { struct thread_robust_arg {
int ti; int ti;
volatile int *global_count; volatile int *global_count;
pthread_mutex_t *mutex; pthread_mutex_t *mutex;
}; };
int ret_err = -1; int ret_err = -1;
static void *thread_worker(void *_arg) { static void *thread_worker(void *_arg)
struct thread_robust_arg *arg = _arg; {
int err = pthread_mutex_lock(arg->mutex); struct thread_robust_arg *arg = _arg;
if (err == EOWNERDEAD) { int err = pthread_mutex_lock(arg->mutex);
// The mutex is locked by the thread here, but the state is marked as if (err == EOWNERDEAD) {
// inconsistent, the thread should call 'pthread_mutex_consistent' to // The mutex is locked by the thread here, but the state is marked as
// make the mutex consistent again. // inconsistent, the thread should call 'pthread_mutex_consistent' to
if (pthread_mutex_consistent(arg->mutex) != 0) { // make the mutex consistent again.
printf("ERROR: failed to recover the mutex\n"); if (pthread_mutex_consistent(arg->mutex) != 0) {
return &ret_err; printf("ERROR: failed to recover the mutex\n");
} return &ret_err;
} else if (err != 0) { }
printf("ERROR: failed to lock the mutex with error: %d\n", err); } else if (err != 0) {
return &ret_err; printf("ERROR: failed to lock the mutex with error: %d\n", err);
} return &ret_err;
// Mutex is locked }
(*arg->global_count)++; // Mutex is locked
// Wait for other threads to acquire the lock (*arg->global_count)++;
sleep(1); // Wait for other threads to acquire the lock
// Exit without unlocking the mutex, this will makes the mutex in an sleep(1);
// inconsistent state. // Exit without unlocking the mutex, this will makes the mutex in an
return NULL; // inconsistent state.
return NULL;
} }
static int test_robust_mutex_with_concurrent_counter(void) { static int test_robust_mutex_with_concurrent_counter(void)
volatile int global_count = 0; {
pthread_t threads[NTHREADS]; volatile int global_count = 0;
struct thread_robust_arg thread_args[NTHREADS]; pthread_t threads[NTHREADS];
// Init robust mutex struct thread_robust_arg thread_args[NTHREADS];
pthread_mutex_t mutex; // Init robust mutex
pthread_mutexattr_t attr; pthread_mutex_t mutex;
pthread_mutexattr_init(&attr); pthread_mutexattr_t attr;
pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST); pthread_mutexattr_init(&attr);
pthread_mutex_init(&mutex, &attr); pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
// Start the threads pthread_mutex_init(&mutex, &attr);
for (int ti = 0; ti < NTHREADS; ti++) { // Start the threads
struct thread_robust_arg *thread_arg = &thread_args[ti]; for (int ti = 0; ti < NTHREADS; ti++) {
thread_arg->ti = ti; struct thread_robust_arg *thread_arg = &thread_args[ti];
thread_arg->global_count = &global_count; thread_arg->ti = ti;
thread_arg->mutex = &mutex; thread_arg->global_count = &global_count;
thread_arg->mutex = &mutex;
if (pthread_create(&threads[ti], NULL, thread_worker, thread_arg) < 0) { if (pthread_create(&threads[ti], NULL, thread_worker,
THROW_ERROR("pthread_create failed (ti = %d)", ti); thread_arg) < 0) {
} THROW_ERROR("pthread_create failed (ti = %d)", ti);
} }
// Wait for the threads to finish }
for (int ti = 0; ti < NTHREADS; ti++) { // Wait for the threads to finish
int *ret_val; for (int ti = 0; ti < NTHREADS; ti++) {
if (pthread_join(threads[ti], (void **)&ret_val) < 0) { int *ret_val;
THROW_ERROR("pthread_join failed (ti = %d)", ti); if (pthread_join(threads[ti], (void **)&ret_val) < 0) {
} THROW_ERROR("pthread_join failed (ti = %d)", ti);
// printf("Thread %d joined\n", ti); }
// fflush(stdout); // printf("Thread %d joined\n", ti);
if (ret_val && *ret_val != 0) { // fflush(stdout);
THROW_ERROR("run thread failed (ti = %d) with return val: %d", ti, *ret_val); if (ret_val && *ret_val != 0) {
} THROW_ERROR(
} "run thread failed (ti = %d) with return val: %d",
// printf("Thread all exited.\n"); ti, *ret_val);
// fflush(stdout); }
// Check the result }
if (global_count != NTHREADS) { // printf("Thread all exited.\n");
THROW_ERROR("incorrect global_count (actual = %d, expected = %d)", global_count, // fflush(stdout);
NTHREADS); // Check the result
} if (global_count != NTHREADS) {
THROW_ERROR(
"incorrect global_count (actual = %d, expected = %d)",
global_count, NTHREADS);
}
pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&mutex);
return 0; return 0;
} }
// ============================================================================ // ============================================================================
// The test case of waiting condition variable // The test case of waiting condition variable
// ============================================================================ // ============================================================================
#define WAIT_ROUND (10) #define WAIT_ROUND (10)
struct thread_cond_arg { struct thread_cond_arg {
int ti; int ti;
volatile unsigned int *val; volatile unsigned int *val;
volatile int *exit_thread_count; volatile int *exit_thread_count;
pthread_cond_t *cond_val; pthread_cond_t *cond_val;
pthread_mutex_t *mutex; pthread_mutex_t *mutex;
}; };
static void *thread_cond_wait(void *_arg) { static void *thread_cond_wait(void *_arg)
struct thread_cond_arg *arg = _arg; {
printf("Thread #%d: start to wait on condition variable.\n", arg->ti); struct thread_cond_arg *arg = _arg;
fflush(stdout); printf("Thread #%d: start to wait on condition variable.\n", arg->ti);
for (unsigned int i = 0; i < WAIT_ROUND; ++i) { fflush(stdout);
int tid = gettid(); for (unsigned int i = 0; i < WAIT_ROUND; ++i) {
printf("WAIT ROUND: %d, tid = %d\n", i, tid); int tid = gettid();
fflush(stdout); printf("WAIT ROUND: %d, tid = %d\n", i, tid);
pthread_mutex_lock(arg->mutex); fflush(stdout);
printf("pthread mutex lock: tid = %d\n", tid); pthread_mutex_lock(arg->mutex);
fflush(stdout); printf("pthread mutex lock: tid = %d\n", tid);
while (*(arg->val) == 0) { fflush(stdout);
pthread_cond_wait(arg->cond_val, arg->mutex); while (*(arg->val) == 0) {
printf("pthread cond wait: tid = %d\n", tid); pthread_cond_wait(arg->cond_val, arg->mutex);
fflush(stdout); printf("pthread cond wait: tid = %d\n", tid);
} fflush(stdout);
pthread_mutex_unlock(arg->mutex); }
} pthread_mutex_unlock(arg->mutex);
(*arg->exit_thread_count)++; }
printf("Thread #%d: exited.\n", arg->ti); (*arg->exit_thread_count)++;
fflush(stdout); printf("Thread #%d: exited.\n", arg->ti);
return NULL; fflush(stdout);
return NULL;
} }
static int test_mutex_with_cond_wait(void) { static int test_mutex_with_cond_wait(void)
volatile unsigned int val = 0; {
volatile int exit_thread_count = 0; volatile unsigned int val = 0;
pthread_t threads[NTHREADS]; volatile int exit_thread_count = 0;
struct thread_cond_arg thread_args[NTHREADS]; pthread_t threads[NTHREADS];
pthread_cond_t cond_val = PTHREAD_COND_INITIALIZER; struct thread_cond_arg thread_args[NTHREADS];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond_val = PTHREAD_COND_INITIALIZER;
/* pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/*
* Start the threads waiting on the condition variable * Start the threads waiting on the condition variable
*/ */
for (int ti = 0; ti < NTHREADS; ti++) { for (int ti = 0; ti < NTHREADS; ti++) {
struct thread_cond_arg *thread_arg = &thread_args[ti]; struct thread_cond_arg *thread_arg = &thread_args[ti];
thread_arg->ti = ti; thread_arg->ti = ti;
thread_arg->val = &val; thread_arg->val = &val;
thread_arg->exit_thread_count = &exit_thread_count; thread_arg->exit_thread_count = &exit_thread_count;
thread_arg->cond_val = &cond_val; thread_arg->cond_val = &cond_val;
thread_arg->mutex = &mutex; thread_arg->mutex = &mutex;
if (pthread_create(&threads[ti], NULL, thread_cond_wait, thread_arg) < 0) { if (pthread_create(&threads[ti], NULL, thread_cond_wait,
printf("ERROR: pthread_create failed (ti = %d)\n", ti); thread_arg) < 0) {
return -1; printf("ERROR: pthread_create failed (ti = %d)\n", ti);
} return -1;
} }
/* }
/*
* Unblock all threads currently waiting on the condition variable * Unblock all threads currently waiting on the condition variable
*/ */
while (exit_thread_count < NTHREADS) { while (exit_thread_count < NTHREADS) {
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
val = 1; val = 1;
pthread_cond_broadcast(&cond_val); pthread_cond_broadcast(&cond_val);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
val = 0; val = 0;
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
} }
/* /*
* Wait for the threads to finish * Wait for the threads to finish
*/ */
for (int ti = 0; ti < NTHREADS; ti++) { for (int ti = 0; ti < NTHREADS; ti++) {
if (pthread_join(threads[ti], NULL) < 0) { if (pthread_join(threads[ti], NULL) < 0) {
printf("ERROR: pthread_join failed (ti = %d)\n", ti); printf("ERROR: pthread_join failed (ti = %d)\n", ti);
return -1; return -1;
} }
} }
return 0; return 0;
} }
int main() { int main()
test_mutex_with_concurrent_counter(); {
test_robust_mutex_with_concurrent_counter(); test_mutex_with_concurrent_counter();
// test_mutex_with_cond_wait(); test_robust_mutex_with_concurrent_counter();
return 0; // test_mutex_with_cond_wait();
return 0;
} }

View File

@ -7,47 +7,48 @@
#include <termios.h> #include <termios.h>
#include <pty.h> #include <pty.h>
int main() { int main()
int master, slave; {
char name[256]; int master, slave;
struct termios term; char name[256];
struct termios term;
if (openpty(&master, &slave, name, NULL, NULL) == -1) { if (openpty(&master, &slave, name, NULL, NULL) == -1) {
perror("openpty"); perror("openpty");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("slave name: %s\n", name); printf("slave name: %s\n", name);
// Set pty slave terminal attributes // Set pty slave terminal attributes
tcgetattr(slave, &term); tcgetattr(slave, &term);
term.c_lflag &= ~(ICANON | ECHO); term.c_lflag &= ~(ICANON | ECHO);
term.c_cc[VMIN] = 1; term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0; term.c_cc[VTIME] = 0;
tcsetattr(slave, TCSANOW, &term); tcsetattr(slave, TCSANOW, &term);
// Print to pty slave // Print to pty slave
dprintf(slave, "Hello world!\n"); dprintf(slave, "Hello world!\n");
// Read from pty slave // Read from pty slave
char buf[256]; char buf[256];
ssize_t n = read(master, buf, sizeof(buf)); ssize_t n = read(master, buf, sizeof(buf));
if (n > 0) { if (n > 0) {
printf("read %ld bytes from slave: %.*s", n, (int)n, buf); printf("read %ld bytes from slave: %.*s", n, (int)n, buf);
} }
// Write to pty master // Write to pty master
dprintf(master, "hello world from master\n"); dprintf(master, "hello world from master\n");
// Read from pty master // Read from pty master
char nbuf[256]; char nbuf[256];
ssize_t nn = read(slave, nbuf, sizeof(nbuf)); ssize_t nn = read(slave, nbuf, sizeof(nbuf));
if (nn > 0) { if (nn > 0) {
printf("read %ld bytes from master: %.*s", nn, (int)nn, nbuf); printf("read %ld bytes from master: %.*s", nn, (int)nn, nbuf);
} }
close(master); close(master);
close(slave); close(slave);
return 0; return 0;
} }

View File

@ -24,12 +24,14 @@
// Helper functions // Helper functions
// ============================================================================ // ============================================================================
#define THROW_ERROR(fmt, ...) do { \ #define THROW_ERROR(fmt, ...) \
printf("\t\tERROR:" fmt " in func %s at line %d of file %s with errno %d: %s\n", \ do { \
##__VA_ARGS__, __func__, __LINE__, __FILE__, errno, strerror(errno)); \ printf("\t\tERROR:" fmt \
return -1; \ " in func %s at line %d of file %s with errno %d: %s\n", \
} while (0) ##__VA_ARGS__, __func__, __LINE__, __FILE__, errno, \
strerror(errno)); \
return -1; \
} while (0)
// ============================================================================ // ============================================================================
// Test sigprocmask // Test sigprocmask
@ -37,216 +39,225 @@
#define sigcmpset(a, b) memcmp((a), (b), 8) #define sigcmpset(a, b) memcmp((a), (b), 8)
int test_sigprocmask() { int test_sigprocmask()
int ret; {
sigset_t new, old; int ret;
sigset_t expected_old; sigset_t new, old;
sigset_t expected_old;
// Check sigmask == [] // Check sigmask == []
if ((ret = sigprocmask(0, NULL, &old)) < 0) { if ((ret = sigprocmask(0, NULL, &old)) < 0) {
THROW_ERROR("sigprocmask failed unexpectedly"); THROW_ERROR("sigprocmask failed unexpectedly");
} }
sigemptyset(&expected_old); sigemptyset(&expected_old);
if (sigcmpset(&old, &expected_old) != 0) { if (sigcmpset(&old, &expected_old) != 0) {
THROW_ERROR("unexpected old sigset"); THROW_ERROR("unexpected old sigset");
} }
// SIG_BLOCK: [] --> [SIGSEGV] // SIG_BLOCK: [] --> [SIGSEGV]
sigemptyset(&new); sigemptyset(&new);
sigaddset(&new, SIGSEGV); sigaddset(&new, SIGSEGV);
if ((ret = sigprocmask(SIG_BLOCK, &new, &old)) < 0) { if ((ret = sigprocmask(SIG_BLOCK, &new, &old)) < 0) {
THROW_ERROR("sigprocmask failed unexpectedly"); THROW_ERROR("sigprocmask failed unexpectedly");
} }
sigemptyset(&expected_old); sigemptyset(&expected_old);
if (sigcmpset(&old, &expected_old) != 0) { if (sigcmpset(&old, &expected_old) != 0) {
THROW_ERROR("unexpected old sigset"); THROW_ERROR("unexpected old sigset");
} }
// SIG_SETMASK: [SIGSEGV] --> [SIGIO] // SIG_SETMASK: [SIGSEGV] --> [SIGIO]
sigemptyset(&new); sigemptyset(&new);
sigaddset(&new, SIGIO); sigaddset(&new, SIGIO);
if ((ret = sigprocmask(SIG_SETMASK, &new, &old)) < 0) { if ((ret = sigprocmask(SIG_SETMASK, &new, &old)) < 0) {
THROW_ERROR("sigprocmask failed unexpectedly"); THROW_ERROR("sigprocmask failed unexpectedly");
} }
sigemptyset(&expected_old); sigemptyset(&expected_old);
sigaddset(&expected_old, SIGSEGV); sigaddset(&expected_old, SIGSEGV);
if (sigcmpset(&old, &expected_old) != 0) { if (sigcmpset(&old, &expected_old) != 0) {
THROW_ERROR("unexpected old sigset"); THROW_ERROR("unexpected old sigset");
} }
// SIG_UNBLOCK: [SIGIO] -> [] // SIG_UNBLOCK: [SIGIO] -> []
if ((ret = sigprocmask(SIG_UNBLOCK, &new, &old)) < 0) { if ((ret = sigprocmask(SIG_UNBLOCK, &new, &old)) < 0) {
THROW_ERROR("sigprocmask failed unexpectedly"); THROW_ERROR("sigprocmask failed unexpectedly");
} }
sigemptyset(&expected_old); sigemptyset(&expected_old);
sigaddset(&expected_old, SIGIO); sigaddset(&expected_old, SIGIO);
if (sigcmpset(&old, &expected_old) != 0) { if (sigcmpset(&old, &expected_old) != 0) {
THROW_ERROR("unexpected old sigset"); THROW_ERROR("unexpected old sigset");
} }
// Check sigmask == [] // Check sigmask == []
if ((ret = sigprocmask(0, NULL, &old)) < 0) { if ((ret = sigprocmask(0, NULL, &old)) < 0) {
THROW_ERROR("sigprocmask failed unexpectedly"); THROW_ERROR("sigprocmask failed unexpectedly");
} }
sigemptyset(&expected_old); sigemptyset(&expected_old);
if (sigcmpset(&old, &expected_old) != 0) { if (sigcmpset(&old, &expected_old) != 0) {
THROW_ERROR("unexpected old sigset"); THROW_ERROR("unexpected old sigset");
} }
return 0; return 0;
} }
// ============================================================================ // ============================================================================
// Test raise syscall and user-registered signal handlers // Test raise syscall and user-registered signal handlers
// ============================================================================ // ============================================================================
#define MAX_RECURSION_LEVEL 3 #define MAX_RECURSION_LEVEL 3
static void handle_sigio(int num, siginfo_t *info, void *context) { static void handle_sigio(int num, siginfo_t *info, void *context)
static volatile int recursion_level = 0; {
printf("Hello from SIGIO signal handler (recursion_level = %d)!\n", recursion_level); static volatile int recursion_level = 0;
fflush(stdout); printf("Hello from SIGIO signal handler (recursion_level = %d)!\n",
recursion_level);
recursion_level++; fflush(stdout);
if (recursion_level <= MAX_RECURSION_LEVEL) {
raise(SIGIO); recursion_level++;
} if (recursion_level <= MAX_RECURSION_LEVEL) {
recursion_level--; raise(SIGIO);
}
recursion_level--;
} }
int test_raise() { int test_raise()
struct sigaction new_action, old_action; {
memset(&new_action, 0, sizeof(struct sigaction)); struct sigaction new_action, old_action;
memset(&old_action, 0, sizeof(struct sigaction)); memset(&new_action, 0, sizeof(struct sigaction));
new_action.sa_sigaction = handle_sigio; memset(&old_action, 0, sizeof(struct sigaction));
new_action.sa_flags = SA_SIGINFO | SA_NODEFER; new_action.sa_sigaction = handle_sigio;
if (sigaction(SIGIO, &new_action, &old_action) < 0) { new_action.sa_flags = SA_SIGINFO | SA_NODEFER;
THROW_ERROR("registering new signal handler failed"); if (sigaction(SIGIO, &new_action, &old_action) < 0) {
} THROW_ERROR("registering new signal handler failed");
if (old_action.sa_handler != SIG_DFL) { }
THROW_ERROR("unexpected old sig handler"); if (old_action.sa_handler != SIG_DFL) {
} THROW_ERROR("unexpected old sig handler");
}
raise(SIGIO); raise(SIGIO);
if (sigaction(SIGIO, &old_action, NULL) < 0) { if (sigaction(SIGIO, &old_action, NULL) < 0) {
THROW_ERROR("restoring old signal handler failed"); THROW_ERROR("restoring old signal handler failed");
} }
return 0; return 0;
} }
// ============================================================================ // ============================================================================
// Test catching and handling hardware exception // Test catching and handling hardware exception
// ============================================================================ // ============================================================================
static void handle_sigfpe(int num, siginfo_t *info, void *_context) { static void handle_sigfpe(int num, siginfo_t *info, void *_context)
printf("SIGFPE Caught\n"); {
fflush(stdout); printf("SIGFPE Caught\n");
assert(num == SIGFPE); fflush(stdout);
assert(info->si_signo == SIGFPE); assert(num == SIGFPE);
ucontext_t *ucontext = _context; assert(info->si_signo == SIGFPE);
mcontext_t *mcontext = &ucontext->uc_mcontext; ucontext_t *ucontext = _context;
// The faulty instruction should be `idiv %esi` (f7 fe) mcontext_t *mcontext = &ucontext->uc_mcontext;
mcontext->gregs[REG_RIP] += 2; // The faulty instruction should be `idiv %esi` (f7 fe)
return; mcontext->gregs[REG_RIP] += 2;
return;
} }
// Note: this function is fragile in the sense that compiler may not always // Note: this function is fragile in the sense that compiler may not always
// emit the instruction pattern that triggers divide-by-zero as we expect. // emit the instruction pattern that triggers divide-by-zero as we expect.
// TODO: rewrite this in assembly // TODO: rewrite this in assembly
int div_maybe_zero(int x, int y) { int div_maybe_zero(int x, int y)
return x / y; {
return x / y;
} }
#define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr))) #define fxsave(addr) __asm __volatile("fxsave %0" : "=m"(*(addr)))
int test_handle_sigfpe() { int test_handle_sigfpe()
// Set up a signal handler that handles divide-by-zero exception {
struct sigaction new_action, old_action; // Set up a signal handler that handles divide-by-zero exception
memset(&new_action, 0, sizeof(struct sigaction)); struct sigaction new_action, old_action;
memset(&old_action, 0, sizeof(struct sigaction)); memset(&new_action, 0, sizeof(struct sigaction));
new_action.sa_sigaction = handle_sigfpe; memset(&old_action, 0, sizeof(struct sigaction));
new_action.sa_flags = SA_SIGINFO; new_action.sa_sigaction = handle_sigfpe;
if (sigaction(SIGFPE, &new_action, &old_action) < 0) { new_action.sa_flags = SA_SIGINFO;
THROW_ERROR("registering new signal handler failed"); if (sigaction(SIGFPE, &new_action, &old_action) < 0) {
} THROW_ERROR("registering new signal handler failed");
if (old_action.sa_handler != SIG_DFL) { }
THROW_ERROR("unexpected old sig handler"); if (old_action.sa_handler != SIG_DFL) {
} THROW_ERROR("unexpected old sig handler");
}
char x[512] __attribute__((aligned(16))) = {}; char x[512] __attribute__((aligned(16))) = {};
char y[512] __attribute__((aligned(16))) = {}; char y[512] __attribute__((aligned(16))) = {};
// Trigger divide-by-zero exception // Trigger divide-by-zero exception
int a = 1; int a = 1;
int b = 0; int b = 0;
// Use volatile to prevent compiler optimization // Use volatile to prevent compiler optimization
volatile int c; volatile int c;
fxsave(x); fxsave(x);
c = div_maybe_zero(a, b); c = div_maybe_zero(a, b);
fxsave(y); fxsave(y);
// Asterinas does not save and restore fpregs now, so we emit this check. // Asterinas does not save and restore fpregs now, so we emit this check.
// if (memcmp(x, y, 512) != 0) { // if (memcmp(x, y, 512) != 0) {
// THROW_ERROR("floating point registers are modified"); // THROW_ERROR("floating point registers are modified");
// } // }
printf("Signal handler successfully jumped over the divide-by-zero instruction\n"); printf("Signal handler successfully jumped over the divide-by-zero instruction\n");
fflush(stdout); fflush(stdout);
if (sigaction(SIGFPE, &old_action, NULL) < 0) { if (sigaction(SIGFPE, &old_action, NULL) < 0) {
THROW_ERROR("restoring old signal handler failed"); THROW_ERROR("restoring old signal handler failed");
} }
return 0; return 0;
} }
// TODO: rewrite this in assembly // TODO: rewrite this in assembly
int read_maybe_null(int *p) { int read_maybe_null(int *p)
return *p; {
return *p;
} }
static void handle_sigsegv(int num, siginfo_t *info, void *_context) { static void handle_sigsegv(int num, siginfo_t *info, void *_context)
printf("SIGSEGV Caught\n"); {
fflush(stdout); printf("SIGSEGV Caught\n");
fflush(stdout);
assert(num == SIGSEGV); assert(num == SIGSEGV);
assert(info->si_signo == SIGSEGV); assert(info->si_signo == SIGSEGV);
ucontext_t *ucontext = _context; ucontext_t *ucontext = _context;
mcontext_t *mcontext = &ucontext->uc_mcontext; mcontext_t *mcontext = &ucontext->uc_mcontext;
// TODO: how long is the instruction? // TODO: how long is the instruction?
// The faulty instruction should be `idiv %esi` (f7 fe) // The faulty instruction should be `idiv %esi` (f7 fe)
mcontext->gregs[REG_RIP] += 2; mcontext->gregs[REG_RIP] += 2;
return; return;
} }
int test_handle_sigsegv()
{
// Set up a signal handler that handles divide-by-zero exception
struct sigaction new_action, old_action;
memset(&new_action, 0, sizeof(struct sigaction));
memset(&old_action, 0, sizeof(struct sigaction));
new_action.sa_sigaction = handle_sigsegv;
new_action.sa_flags = SA_SIGINFO;
if (sigaction(SIGSEGV, &new_action, &old_action) < 0) {
THROW_ERROR("registering new signal handler failed");
}
if (old_action.sa_handler != SIG_DFL) {
THROW_ERROR("unexpected old sig handler");
}
int test_handle_sigsegv() { int *addr = NULL;
// Set up a signal handler that handles divide-by-zero exception volatile int val = read_maybe_null(addr);
struct sigaction new_action, old_action; (void)val; // to suppress "unused variables" warning
memset(&new_action, 0, sizeof(struct sigaction));
memset(&old_action, 0, sizeof(struct sigaction));
new_action.sa_sigaction = handle_sigsegv;
new_action.sa_flags = SA_SIGINFO;
if (sigaction(SIGSEGV, &new_action, &old_action) < 0) {
THROW_ERROR("registering new signal handler failed");
}
if (old_action.sa_handler != SIG_DFL) {
THROW_ERROR("unexpected old sig handler");
}
int *addr = NULL; printf("Signal handler successfully jumped over a null-dereferencing instruction\n");
volatile int val = read_maybe_null(addr); fflush(stdout);
(void)val; // to suppress "unused variables" warning
printf("Signal handler successfully jumped over a null-dereferencing instruction\n"); if (sigaction(SIGSEGV, &old_action, NULL) < 0) {
fflush(stdout); THROW_ERROR("restoring old signal handler failed");
}
if (sigaction(SIGSEGV, &old_action, NULL) < 0) { return 0;
THROW_ERROR("restoring old signal handler failed");
}
return 0;
} }
// ============================================================================ // ============================================================================
@ -254,105 +265,111 @@ int test_handle_sigsegv() {
// ============================================================================ // ============================================================================
int sigchld = 0; int sigchld = 0;
void proc_exit() { void proc_exit()
sigchld = 1; {
sigchld = 1;
} }
int test_sigchld() { int test_sigchld()
signal(SIGCHLD, proc_exit); {
printf("Run a parent process has pid = %d\n", getpid()); signal(SIGCHLD, proc_exit);
fflush(stdout); printf("Run a parent process has pid = %d\n", getpid());
int pid = fork(); fflush(stdout);
if(pid == 0) { int pid = fork();
// child process if (pid == 0) {
printf("create a new proces successfully (pid = %d)\n", getpid()); // child process
fflush(stdout); printf("create a new proces successfully (pid = %d)\n",
exit(0); getpid());
} else { fflush(stdout);
// parent process exit(0);
wait(NULL); } else {
printf("sigchld = %d\n", sigchld); // parent process
fflush(stdout); wait(NULL);
} printf("sigchld = %d\n", sigchld);
return 0; fflush(stdout);
}
return 0;
} }
// ============================================================================ // ============================================================================
// Test handle signal on alternate signal stack // Test handle signal on alternate signal stack
// ============================================================================ // ============================================================================
#define MAX_ALTSTACK_RECURSION_LEVEL 2 #define MAX_ALTSTACK_RECURSION_LEVEL 2
stack_t g_old_ss; stack_t g_old_ss;
static void handle_sigpipe(int num, siginfo_t *info, void *context) { static void handle_sigpipe(int num, siginfo_t *info, void *context)
static volatile int recursion_level = 0; {
printf("Hello from SIGPIPE signal handler on the alternate signal stack (recursion_level = %d)\n", static volatile int recursion_level = 0;
recursion_level); printf("Hello from SIGPIPE signal handler on the alternate signal stack (recursion_level = %d)\n",
recursion_level);
// save old_ss to check if we are on stack // save old_ss to check if we are on stack
stack_t old_ss; stack_t old_ss;
sigaltstack(NULL, &old_ss); sigaltstack(NULL, &old_ss);
g_old_ss = old_ss; g_old_ss = old_ss;
recursion_level++; recursion_level++;
if (recursion_level <= MAX_ALTSTACK_RECURSION_LEVEL) { if (recursion_level <= MAX_ALTSTACK_RECURSION_LEVEL) {
raise(SIGPIPE); raise(SIGPIPE);
} }
recursion_level--; recursion_level--;
} }
#define SIGSTACKSIZE (4*4096) #define SIGSTACKSIZE (4 * 4096)
int test_sigaltstack() { int test_sigaltstack()
static char stack[SIGSTACKSIZE]; {
stack_t expected_ss = { static char stack[SIGSTACKSIZE];
.ss_size = SIGSTACKSIZE, stack_t expected_ss = {
.ss_sp = stack, .ss_size = SIGSTACKSIZE,
.ss_flags = 0, .ss_sp = stack,
}; .ss_flags = 0,
if (sigaltstack(&expected_ss, NULL) < 0) { };
THROW_ERROR("failed to call sigaltstack"); if (sigaltstack(&expected_ss, NULL) < 0) {
} THROW_ERROR("failed to call sigaltstack");
stack_t actual_ss; }
if (sigaltstack(NULL, &actual_ss) < 0) { stack_t actual_ss;
THROW_ERROR("failed to call sigaltstack"); if (sigaltstack(NULL, &actual_ss) < 0) {
} THROW_ERROR("failed to call sigaltstack");
if (actual_ss.ss_size != expected_ss.ss_size }
|| actual_ss.ss_sp != expected_ss.ss_sp if (actual_ss.ss_size != expected_ss.ss_size ||
|| actual_ss.ss_flags != expected_ss.ss_flags) { actual_ss.ss_sp != expected_ss.ss_sp ||
THROW_ERROR("failed to check the signal stack after set"); actual_ss.ss_flags != expected_ss.ss_flags) {
} THROW_ERROR("failed to check the signal stack after set");
}
struct sigaction new_action, old_action; struct sigaction new_action, old_action;
memset(&new_action, 0, sizeof(struct sigaction)); memset(&new_action, 0, sizeof(struct sigaction));
memset(&old_action, 0, sizeof(struct sigaction)); memset(&old_action, 0, sizeof(struct sigaction));
new_action.sa_sigaction = handle_sigpipe; new_action.sa_sigaction = handle_sigpipe;
new_action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK; new_action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
if (sigaction(SIGPIPE, &new_action, &old_action) < 0) { if (sigaction(SIGPIPE, &new_action, &old_action) < 0) {
THROW_ERROR("registering new signal handler failed"); THROW_ERROR("registering new signal handler failed");
} }
if (old_action.sa_handler != SIG_DFL) { if (old_action.sa_handler != SIG_DFL) {
THROW_ERROR("unexpected old sig handler"); THROW_ERROR("unexpected old sig handler");
} }
raise(SIGPIPE); raise(SIGPIPE);
if (g_old_ss.ss_flags != SS_ONSTACK) { if (g_old_ss.ss_flags != SS_ONSTACK) {
THROW_ERROR("check stack flags failed"); THROW_ERROR("check stack flags failed");
} }
if (sigaction(SIGPIPE, &old_action, NULL) < 0) { if (sigaction(SIGPIPE, &old_action, NULL) < 0) {
THROW_ERROR("restoring old signal handler failed"); THROW_ERROR("restoring old signal handler failed");
} }
return 0; return 0;
} }
int main() { int main()
test_sigprocmask(); {
test_raise(); test_sigprocmask();
test_handle_sigfpe(); test_raise();
test_handle_sigsegv(); test_handle_sigfpe();
test_sigchld(); test_handle_sigsegv();
test_sigaltstack(); test_sigchld();
return 0; test_sigaltstack();
return 0;
} }