Skip to content

Commit fb360be

Browse files
committed
Add IPC shared memory example using the ipc.h API
Signed-off-by: Lukasz Dorau <[email protected]>
1 parent 4d42509 commit fb360be

File tree

6 files changed

+496
-3
lines changed

6 files changed

+496
-3
lines changed

CMakeLists.txt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,13 @@ install(FILES ${CMAKE_SOURCE_DIR}/LICENSE.TXT
437437
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}/")
438438

439439
install(
440-
FILES examples/basic/gpu_shared_memory.c examples/basic/utils_level_zero.h
441-
examples/basic/basic.c examples/basic/ipc_level_zero.c
440+
FILES examples/basic/gpu_shared_memory.c
441+
examples/basic/utils_level_zero.h
442+
examples/basic/basic.c
443+
examples/basic/ipc_level_zero.c
444+
examples/basic/ipc_shm_ipcapi.sh
445+
examples/basic/ipc_shm_ipcapi_consumer.c
446+
examples/basic/ipc_shm_ipcapi_producer.c
442447
DESTINATION "${CMAKE_INSTALL_DOCDIR}/examples")
443448

444449
# Add the include directory and the headers target to the install.

examples/CMakeLists.txt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,37 @@ else()
108108
"UMF_BUILD_LEVEL_ZERO_PROVIDER, UMF_BUILD_LIBUMF_POOL_DISJOINT and "
109109
"UMF_ENABLE_POOL_TRACKING to be turned ON - skipping")
110110
endif()
111+
112+
if(LINUX AND UMF_BUILD_LIBUMF_POOL_JEMALLOC)
113+
set(BASE_NAME ipc_shm_ipcapi)
114+
set(EXAMPLE_NAME umf_example_${BASE_NAME})
115+
116+
foreach(loop_var IN ITEMS "producer" "consumer")
117+
set(EX_NAME ${EXAMPLE_NAME}_${loop_var})
118+
add_umf_executable(
119+
NAME ${EX_NAME}
120+
SRCS basic/${BASE_NAME}_${loop_var}.c
121+
LIBS umf jemalloc_pool)
122+
123+
target_include_directories(
124+
${EX_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils
125+
${UMF_CMAKE_SOURCE_DIR}/include)
126+
127+
target_link_directories(${EX_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS})
128+
endforeach(loop_var)
129+
130+
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/basic/${BASE_NAME}.sh
131+
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
132+
133+
add_test(
134+
NAME ${EXAMPLE_NAME}
135+
COMMAND ${BASE_NAME}.sh
136+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
137+
138+
set_tests_properties(${EXAMPLE_NAME} PROPERTIES LABELS "example")
139+
else()
140+
message(
141+
STATUS
142+
"IPC shared memory example with UMF pool API is supported on Linux only - skipping"
143+
)
144+
endif()

examples/basic/ipc_shm_ipcapi.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#
2+
# Copyright (C) 2024 Intel Corporation
3+
#
4+
# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
5+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
#
7+
8+
#!/bin/bash
9+
10+
# port should be a number from the range <1024, 65535>
11+
PORT=$(( 1024 + ( $$ % ( 65535 - 1024 ))))
12+
13+
# The ipc_shm_ipcapi example requires using pidfd_getfd(2)
14+
# to obtain a duplicate of another process's file descriptor.
15+
# Permission to duplicate another process's file descriptor
16+
# is governed by a ptrace access mode PTRACE_MODE_ATTACH_REALCREDS check (see ptrace(2))
17+
# that can be changed using the /proc/sys/kernel/yama/ptrace_scope interface.
18+
PTRACE_SCOPE_FILE="/proc/sys/kernel/yama/ptrace_scope"
19+
VAL=0
20+
if [ -f $PTRACE_SCOPE_FILE ]; then
21+
PTRACE_SCOPE_VAL=$(cat $PTRACE_SCOPE_FILE)
22+
if [ $PTRACE_SCOPE_VAL -ne $VAL ]; then
23+
echo "Setting ptrace_scope to 0 (classic ptrace permissions) ..."
24+
echo "$ sudo bash -c \"echo $VAL > $PTRACE_SCOPE_FILE\""
25+
sudo bash -c "echo $VAL > $PTRACE_SCOPE_FILE"
26+
fi
27+
PTRACE_SCOPE_VAL=$(cat $PTRACE_SCOPE_FILE)
28+
if [ $PTRACE_SCOPE_VAL -ne $VAL ]; then
29+
echo "SKIP: setting ptrace_scope to 0 (classic ptrace permissions) FAILED - skipping the test"
30+
exit 0
31+
fi
32+
fi
33+
34+
echo "Starting ipc_shm_ipcapi CONSUMER on port $PORT ..."
35+
./umf_example_ipc_shm_ipcapi_consumer $PORT &
36+
37+
echo "Waiting 1 sec ..."
38+
sleep 1
39+
40+
echo "Starting ipc_shm_ipcapi PRODUCER on port $PORT ..."
41+
./umf_example_ipc_shm_ipcapi_producer $PORT
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/*
2+
* Copyright (C) 2024 Intel Corporation
3+
*
4+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
5+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
*/
7+
8+
#include <arpa/inet.h>
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
#include <string.h>
12+
#include <sys/socket.h>
13+
#include <unistd.h>
14+
15+
#include <umf/ipc.h>
16+
#include <umf/memory_pool.h>
17+
#include <umf/pools/pool_jemalloc.h>
18+
#include <umf/providers/provider_os_memory.h>
19+
20+
#define INET_ADDR "127.0.0.1"
21+
#define CONSUMER_MSG_SIZE 256
22+
#define RECV_BUFF_SIZE 1024
23+
24+
// consumer's response message
25+
#define CONSUMER_MSG \
26+
"This is the consumer. I just wrote a new number directly into your " \
27+
"shared memory!"
28+
29+
int main(int argc, char *argv[]) {
30+
struct sockaddr_in consumer_addr;
31+
struct sockaddr_in producer_addr;
32+
char consumer_message[CONSUMER_MSG_SIZE];
33+
char recv_buffer[RECV_BUFF_SIZE];
34+
int producer_socket;
35+
int producer_addr_len;
36+
int consumer_socket;
37+
int ret = -1;
38+
39+
if (argc < 2) {
40+
fprintf(stderr, "usage: %s port\n", argv[0]);
41+
return -1;
42+
}
43+
44+
int port = atoi(argv[1]);
45+
46+
umf_memory_provider_handle_t OS_memory_provider = NULL;
47+
umf_os_memory_provider_params_t os_params;
48+
enum umf_result_t umf_result;
49+
50+
os_params = umfOsMemoryProviderParamsDefault();
51+
os_params.flag = UMF_MEM_MAP_SHARED;
52+
53+
// create OS memory provider
54+
umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_params,
55+
&OS_memory_provider);
56+
if (umf_result != UMF_RESULT_SUCCESS) {
57+
fprintf(stderr,
58+
"[consumer] ERROR: creating OS memory provider failed\n");
59+
return -1;
60+
}
61+
62+
umf_memory_pool_handle_t jemalloc_pool;
63+
umf_result = umfPoolCreate(umfJemallocPoolOps(), OS_memory_provider, NULL,
64+
0, &jemalloc_pool);
65+
if (umf_result != UMF_RESULT_SUCCESS) {
66+
fprintf(stderr,
67+
"[producer] ERROR: creating jemalloc UMF pool failed\n");
68+
goto err_destroy_OS_memory_provider;
69+
}
70+
71+
// create socket
72+
consumer_socket = socket(AF_INET, SOCK_STREAM, 0);
73+
if (consumer_socket < 0) {
74+
fprintf(stderr, "[consumer] ERROR: creating socket failed\n");
75+
goto err_destroy_jemalloc_pool;
76+
}
77+
78+
fprintf(stderr, "[consumer] Socket created\n");
79+
80+
// set port and IP address
81+
consumer_addr.sin_family = AF_INET;
82+
consumer_addr.sin_port = htons(port);
83+
consumer_addr.sin_addr.s_addr = inet_addr(INET_ADDR);
84+
85+
// bind to the IP address and port
86+
if (bind(consumer_socket, (struct sockaddr *)&consumer_addr,
87+
sizeof(consumer_addr)) < 0) {
88+
fprintf(stderr, "[consumer] ERROR: cannot bind to the port\n");
89+
goto err_close_consumer_socket;
90+
}
91+
92+
fprintf(stderr, "[consumer] Binding done\n");
93+
94+
// listen for the producer
95+
if (listen(consumer_socket, 1) < 0) {
96+
fprintf(stderr, "[consumer] ERROR: listen() failed\n");
97+
goto err_close_consumer_socket;
98+
}
99+
100+
fprintf(stderr, "[consumer] Listening for incoming connections ...\n");
101+
102+
// accept an incoming connection
103+
producer_addr_len = sizeof(producer_addr);
104+
producer_socket = accept(consumer_socket, (struct sockaddr *)&producer_addr,
105+
(socklen_t *)&producer_addr_len);
106+
if (producer_socket < 0) {
107+
fprintf(stderr, "[consumer] ERROR: accept() failed\n");
108+
goto err_close_consumer_socket;
109+
}
110+
111+
fprintf(stderr, "[consumer] Producer connected at IP %s and port %i\n",
112+
inet_ntoa(producer_addr.sin_addr), ntohs(producer_addr.sin_port));
113+
114+
// receive the IPC handle from the producer's
115+
ssize_t len = recv(producer_socket, recv_buffer, RECV_BUFF_SIZE, 0);
116+
if (len < 0) {
117+
fprintf(stderr, "[consumer] ERROR: recv() failed\n");
118+
goto err_close_producer_socket;
119+
}
120+
121+
umf_ipc_handle_t IPC_handle = (umf_ipc_handle_t)recv_buffer;
122+
123+
fprintf(
124+
stderr,
125+
"[consumer] Received the IPC handle from the producer (%zi bytes)\n",
126+
len);
127+
128+
void *SHM_ptr;
129+
umf_result = umfOpenIPCHandle(jemalloc_pool, IPC_handle, &SHM_ptr);
130+
if (umf_result != UMF_RESULT_SUCCESS) {
131+
fprintf(stderr, "[consumer] ERROR: opening the IPC handle failed\n");
132+
goto err_close_producer_socket;
133+
}
134+
135+
fprintf(stderr,
136+
"[consumer] Opened the IPC handle received from the producer\n");
137+
138+
// read the current value from the shared memory
139+
unsigned long long SHM_number_1 = *(unsigned long long *)SHM_ptr;
140+
fprintf(
141+
stderr,
142+
"[consumer] Read the number from the producer's shared memory: %llu\n",
143+
SHM_number_1);
144+
145+
// calculate the new value
146+
unsigned long long SHM_number_2 = SHM_number_1 / 2;
147+
148+
// write the new number directly to the producer's shared memory
149+
*(unsigned long long *)SHM_ptr = SHM_number_2;
150+
fprintf(stderr,
151+
"[consumer] Wrote a new number directly to the producer's shared "
152+
"memory: %llu\n",
153+
SHM_number_2);
154+
155+
// write the response to the consumer_message buffer
156+
memset(consumer_message, 0, sizeof(consumer_message));
157+
strcpy(consumer_message, CONSUMER_MSG);
158+
159+
// send response to the producer
160+
if (send(producer_socket, consumer_message, strlen(consumer_message) + 1,
161+
0) < 0) {
162+
fprintf(stderr, "[consumer] ERROR: send() failed\n");
163+
goto err_CloseIPCHandle;
164+
}
165+
166+
fprintf(stderr, "[consumer] Sent a response message to the producer\n");
167+
168+
ret = 0; // SUCCESS
169+
170+
err_CloseIPCHandle:
171+
umf_result = umfCloseIPCHandle(SHM_ptr);
172+
if (umf_result != UMF_RESULT_SUCCESS) {
173+
fprintf(stderr, "[consumer] ERROR: closing the IPC handle failed\n");
174+
}
175+
176+
fprintf(stderr,
177+
"[consumer] Closed the IPC handle received from the producer\n");
178+
179+
err_close_producer_socket:
180+
close(producer_socket);
181+
182+
err_close_consumer_socket:
183+
close(consumer_socket);
184+
185+
err_destroy_jemalloc_pool:
186+
umfPoolDestroy(jemalloc_pool);
187+
188+
err_destroy_OS_memory_provider:
189+
umfMemoryProviderDestroy(OS_memory_provider);
190+
191+
if (ret == 0) {
192+
fprintf(stderr, "[consumer] Shutting down (status OK) ...\n");
193+
} else {
194+
fprintf(stderr, "[consumer] Shutting down (status ERROR) ...\n");
195+
}
196+
197+
return ret;
198+
}

0 commit comments

Comments
 (0)