NVIDIA_cuda-samples
555 строк · 15.4 Кб
1/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
2*
3* Redistribution and use in source and binary forms, with or without
4* modification, are permitted provided that the following conditions
5* are met:
6* * Redistributions of source code must retain the above copyright
7* notice, this list of conditions and the following disclaimer.
8* * Redistributions in binary form must reproduce the above copyright
9* notice, this list of conditions and the following disclaimer in the
10* documentation and/or other materials provided with the distribution.
11* * Neither the name of NVIDIA CORPORATION nor the names of its
12* contributors may be used to endorse or promote products derived
13* from this software without specific prior written permission.
14*
15* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
16* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
19* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include "helper_multiprocess.h"
29#include <cstdlib>
30#include <string>
31
32int sharedMemoryCreate(const char *name, size_t sz, sharedMemoryInfo *info) {
33#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
34info->size = sz;
35info->shmHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
36PAGE_READWRITE, 0, (DWORD)sz, name);
37if (info->shmHandle == 0) {
38return GetLastError();
39}
40
41info->addr = MapViewOfFile(info->shmHandle, FILE_MAP_ALL_ACCESS, 0, 0, sz);
42if (info->addr == NULL) {
43return GetLastError();
44}
45
46return 0;
47#else
48int status = 0;
49
50info->size = sz;
51
52info->shmFd = shm_open(name, O_RDWR | O_CREAT, 0777);
53if (info->shmFd < 0) {
54return errno;
55}
56
57status = ftruncate(info->shmFd, sz);
58if (status != 0) {
59return status;
60}
61
62info->addr = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, info->shmFd, 0);
63if (info->addr == NULL) {
64return errno;
65}
66
67return 0;
68#endif
69}
70
71int sharedMemoryOpen(const char *name, size_t sz, sharedMemoryInfo *info) {
72#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
73info->size = sz;
74
75info->shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name);
76if (info->shmHandle == 0) {
77return GetLastError();
78}
79
80info->addr = MapViewOfFile(info->shmHandle, FILE_MAP_ALL_ACCESS, 0, 0, sz);
81if (info->addr == NULL) {
82return GetLastError();
83}
84
85return 0;
86#else
87info->size = sz;
88
89info->shmFd = shm_open(name, O_RDWR, 0777);
90if (info->shmFd < 0) {
91return errno;
92}
93
94info->addr = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, info->shmFd, 0);
95if (info->addr == NULL) {
96return errno;
97}
98
99return 0;
100#endif
101}
102
103void sharedMemoryClose(sharedMemoryInfo *info) {
104#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
105if (info->addr) {
106UnmapViewOfFile(info->addr);
107}
108if (info->shmHandle) {
109CloseHandle(info->shmHandle);
110}
111#else
112if (info->addr) {
113munmap(info->addr, info->size);
114}
115if (info->shmFd) {
116close(info->shmFd);
117}
118#endif
119}
120
121int spawnProcess(Process *process, const char *app, char *const *args) {
122#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
123STARTUPINFO si = {0};
124BOOL status;
125size_t arglen = 0;
126size_t argIdx = 0;
127std::string arg_string;
128memset(process, 0, sizeof(*process));
129
130while (*args) {
131arg_string.append(*args).append(1, ' ');
132args++;
133}
134
135status = CreateProcess(app, LPSTR(arg_string.c_str()), NULL, NULL, FALSE, 0,
136NULL, NULL, &si, process);
137
138return status ? 0 : GetLastError();
139#else
140*process = fork();
141if (*process == 0) {
142if (0 > execvp(app, args)) {
143return errno;
144}
145} else if (*process < 0) {
146return errno;
147}
148return 0;
149#endif
150}
151
152int waitProcess(Process *process) {
153#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
154DWORD exitCode;
155WaitForSingleObject(process->hProcess, INFINITE);
156GetExitCodeProcess(process->hProcess, &exitCode);
157CloseHandle(process->hProcess);
158CloseHandle(process->hThread);
159return (int)exitCode;
160#else
161int status = 0;
162do {
163if (0 > waitpid(*process, &status, 0)) {
164return errno;
165}
166} while (!WIFEXITED(status));
167return WEXITSTATUS(status);
168#endif
169}
170
171#if defined(__linux__) || defined(__QNX__)
172int ipcCreateSocket(ipcHandle *&handle, const char *name,
173const std::vector<Process> &processes) {
174int server_fd;
175struct sockaddr_un servaddr;
176
177handle = new ipcHandle;
178memset(handle, 0, sizeof(*handle));
179handle->socket = -1;
180handle->socketName = NULL;
181
182// Creating socket file descriptor
183if ((server_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == 0) {
184perror("IPC failure: Socket creation failed");
185return -1;
186}
187
188unlink(name);
189bzero(&servaddr, sizeof(servaddr));
190servaddr.sun_family = AF_UNIX;
191
192size_t len = strlen(name);
193if (len > (sizeof(servaddr.sun_path) - 1)) {
194perror("IPC failure: Cannot bind provided name to socket. Name too large");
195return -1;
196}
197
198strncpy(servaddr.sun_path, name, len);
199
200if (bind(server_fd, (struct sockaddr *)&servaddr, SUN_LEN(&servaddr)) < 0) {
201perror("IPC failure: Binding socket failed");
202return -1;
203}
204
205handle->socketName = new char[strlen(name) + 1];
206strcpy(handle->socketName, name);
207handle->socket = server_fd;
208return 0;
209}
210
211int ipcOpenSocket(ipcHandle *&handle) {
212int sock = 0;
213struct sockaddr_un cliaddr;
214
215handle = new ipcHandle;
216memset(handle, 0, sizeof(*handle));
217
218if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
219perror("IPC failure:Socket creation error");
220return -1;
221}
222
223bzero(&cliaddr, sizeof(cliaddr));
224cliaddr.sun_family = AF_UNIX;
225char temp[10];
226
227// Create unique name for the socket.
228sprintf(temp, "%u", getpid());
229
230strcpy(cliaddr.sun_path, temp);
231if (bind(sock, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0) {
232perror("IPC failure: Binding socket failed");
233return -1;
234}
235
236handle->socket = sock;
237handle->socketName = new char[strlen(temp) + 1];
238strcpy(handle->socketName, temp);
239
240return 0;
241}
242
243int ipcCloseSocket(ipcHandle *handle) {
244if (!handle) {
245return -1;
246}
247
248if (handle->socketName) {
249unlink(handle->socketName);
250delete[] handle->socketName;
251}
252close(handle->socket);
253delete handle;
254return 0;
255}
256
257int ipcRecvShareableHandle(ipcHandle *handle, ShareableHandle *shHandle) {
258struct msghdr msg = {0};
259struct iovec iov[1];
260struct cmsghdr cm;
261
262// Union to guarantee alignment requirements for control array
263union {
264struct cmsghdr cm;
265// This will not work on QNX as QNX CMSG_SPACE calls __cmsg_alignbytes
266// And __cmsg_alignbytes is a runtime function instead of compile-time macros
267// char control[CMSG_SPACE(sizeof(int))]
268char* control;
269} control_un;
270
271size_t sizeof_control = CMSG_SPACE(sizeof(int)) * sizeof(char);
272control_un.control = (char*) malloc(sizeof_control);
273struct cmsghdr *cmptr;
274ssize_t n;
275int receivedfd;
276char dummy_buffer[1];
277ssize_t sendResult;
278msg.msg_control = control_un.control;
279msg.msg_controllen = sizeof_control;
280
281iov[0].iov_base = (void *)dummy_buffer;
282iov[0].iov_len = sizeof(dummy_buffer);
283
284msg.msg_iov = iov;
285msg.msg_iovlen = 1;
286if ((n = recvmsg(handle->socket, &msg, 0)) <= 0) {
287perror("IPC failure: Receiving data over socket failed");
288free(control_un.control);
289return -1;
290}
291
292if (((cmptr = CMSG_FIRSTHDR(&msg)) != NULL) &&
293(cmptr->cmsg_len == CMSG_LEN(sizeof(int)))) {
294if ((cmptr->cmsg_level != SOL_SOCKET) || (cmptr->cmsg_type != SCM_RIGHTS)) {
295free(control_un.control);
296return -1;
297}
298
299memmove(&receivedfd, CMSG_DATA(cmptr), sizeof(receivedfd));
300*(int *)shHandle = receivedfd;
301} else {
302free(control_un.control);
303return -1;
304}
305
306free(control_un.control);
307return 0;
308}
309
310int ipcRecvDataFromClient(ipcHandle *serverHandle, void *data, size_t size) {
311ssize_t readResult;
312struct sockaddr_un cliaddr;
313socklen_t len = sizeof(cliaddr);
314
315readResult = recvfrom(serverHandle->socket, data, size, 0,
316(struct sockaddr *)&cliaddr, &len);
317if (readResult == -1) {
318perror("IPC failure: Receiving data over socket failed");
319return -1;
320}
321return 0;
322}
323
324int ipcSendDataToServer(ipcHandle *handle, const char *serverName,
325const void *data, size_t size) {
326ssize_t sendResult;
327struct sockaddr_un serveraddr;
328
329bzero(&serveraddr, sizeof(serveraddr));
330serveraddr.sun_family = AF_UNIX;
331strncpy(serveraddr.sun_path, serverName, sizeof(serveraddr.sun_path) - 1);
332
333sendResult = sendto(handle->socket, data, size, 0,
334(struct sockaddr *)&serveraddr, sizeof(serveraddr));
335if (sendResult <= 0) {
336perror("IPC failure: Sending data over socket failed");
337}
338
339return 0;
340}
341
342int ipcSendShareableHandle(ipcHandle *handle,
343const std::vector<ShareableHandle> &shareableHandles,
344Process process, int data) {
345struct msghdr msg;
346struct iovec iov[1];
347
348union {
349struct cmsghdr cm;
350char* control;
351} control_un;
352
353size_t sizeof_control = CMSG_SPACE(sizeof(int)) * sizeof(char);
354control_un.control = (char*) malloc(sizeof_control);
355
356struct cmsghdr *cmptr;
357ssize_t readResult;
358struct sockaddr_un cliaddr;
359socklen_t len = sizeof(cliaddr);
360
361// Construct client address to send this SHareable handle to
362bzero(&cliaddr, sizeof(cliaddr));
363cliaddr.sun_family = AF_UNIX;
364char temp[10];
365sprintf(temp, "%u", process);
366strcpy(cliaddr.sun_path, temp);
367len = sizeof(cliaddr);
368
369// Send corresponding shareable handle to the client
370int sendfd = (int)shareableHandles[data];
371
372msg.msg_control = control_un.control;
373msg.msg_controllen = sizeof_control;
374
375cmptr = CMSG_FIRSTHDR(&msg);
376cmptr->cmsg_len = CMSG_LEN(sizeof(int));
377cmptr->cmsg_level = SOL_SOCKET;
378cmptr->cmsg_type = SCM_RIGHTS;
379
380memmove(CMSG_DATA(cmptr), &sendfd, sizeof(sendfd));
381
382msg.msg_name = (void *)&cliaddr;
383msg.msg_namelen = sizeof(struct sockaddr_un);
384
385iov[0].iov_base = (void *)"";
386iov[0].iov_len = 1;
387msg.msg_iov = iov;
388msg.msg_iovlen = 1;
389
390ssize_t sendResult = sendmsg(handle->socket, &msg, 0);
391if (sendResult <= 0) {
392perror("IPC failure: Sending data over socket failed");
393free(control_un.control);
394return -1;
395}
396
397free(control_un.control);
398return 0;
399}
400
401int ipcSendShareableHandles(
402ipcHandle *handle, const std::vector<ShareableHandle> &shareableHandles,
403const std::vector<Process> &processes) {
404// Send all shareable handles to every single process.
405for (int i = 0; i < shareableHandles.size(); i++) {
406for (int j = 0; j < processes.size(); j++) {
407checkIpcErrors(
408ipcSendShareableHandle(handle, shareableHandles, processes[j], i));
409}
410}
411return 0;
412}
413
414int ipcRecvShareableHandles(ipcHandle *handle,
415std::vector<ShareableHandle> &shareableHandles) {
416for (int i = 0; i < shareableHandles.size(); i++) {
417checkIpcErrors(ipcRecvShareableHandle(handle, &shareableHandles[i]));
418}
419return 0;
420}
421
422int ipcCloseShareableHandle(ShareableHandle shHandle) {
423return close(shHandle);
424}
425
426#elif defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
427// Generic name to build individual Mailslot names by appending process ids.
428LPTSTR SlotName = (LPTSTR)TEXT("\\\\.\\mailslot\\sample_mailslot_");
429
430int ipcCreateSocket(ipcHandle *&handle, const char *name,
431const std::vector<Process> &processes) {
432handle = new ipcHandle;
433handle->hMailslot.resize(processes.size());
434
435// Open Mailslots of all clients and store respective handles.
436for (int i = 0; i < handle->hMailslot.size(); ++i) {
437std::basic_string<TCHAR> childSlotName(SlotName);
438char tempBuf[20];
439_itoa_s(processes[i].dwProcessId, tempBuf, 10);
440childSlotName += TEXT(tempBuf);
441
442HANDLE hFile =
443CreateFile(TEXT(childSlotName.c_str()), GENERIC_WRITE, FILE_SHARE_READ,
444(LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING,
445FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
446if (hFile == INVALID_HANDLE_VALUE) {
447printf("IPC failure: Opening Mailslot by CreateFile failed with %d\n",
448GetLastError());
449return -1;
450}
451handle->hMailslot[i] = hFile;
452}
453return 0;
454}
455
456int ipcOpenSocket(ipcHandle *&handle) {
457handle = new ipcHandle;
458HANDLE hSlot;
459
460std::basic_string<TCHAR> clientSlotName(SlotName);
461char tempBuf[20];
462_itoa_s(GetCurrentProcessId(), tempBuf, 10);
463clientSlotName += TEXT(tempBuf);
464
465hSlot = CreateMailslot((LPSTR)clientSlotName.c_str(), 0,
466MAILSLOT_WAIT_FOREVER, (LPSECURITY_ATTRIBUTES)NULL);
467if (hSlot == INVALID_HANDLE_VALUE) {
468printf("IPC failure: CreateMailslot failed for client with %d\n",
469GetLastError());
470return -1;
471}
472
473handle->hMailslot.push_back(hSlot);
474return 0;
475}
476
477int ipcSendData(HANDLE mailslot, const void *data, size_t sz) {
478BOOL result;
479DWORD cbWritten;
480
481result = WriteFile(mailslot, data, (DWORD)sz, &cbWritten, (LPOVERLAPPED)NULL);
482if (!result) {
483printf("IPC failure: WriteFile failed with %d.\n", GetLastError());
484return -1;
485}
486return 0;
487}
488
489int ipcRecvData(ipcHandle *handle, void *data, size_t sz) {
490DWORD cbRead = 0;
491
492if (!ReadFile(handle->hMailslot[0], data, (DWORD)sz, &cbRead, NULL)) {
493printf("IPC failure: ReadFile failed with %d.\n", GetLastError());
494return -1;
495}
496
497if (sz != (size_t)cbRead) {
498printf(
499"IPC failure: ReadFile didn't receive the expected number of bytes\n");
500return -1;
501}
502
503return 0;
504}
505
506int ipcSendShareableHandles(
507ipcHandle *handle, const std::vector<ShareableHandle> &shareableHandles,
508const std::vector<Process> &processes) {
509// Send all shareable handles to every single process.
510for (int i = 0; i < processes.size(); i++) {
511HANDLE hProcess =
512OpenProcess(PROCESS_DUP_HANDLE, FALSE, processes[i].dwProcessId);
513if (hProcess == INVALID_HANDLE_VALUE) {
514printf("IPC failure: OpenProcess failed (%d)\n", GetLastError());
515return -1;
516}
517
518for (int j = 0; j < shareableHandles.size(); j++) {
519HANDLE hDup = INVALID_HANDLE_VALUE;
520// Duplicate the handle into the target process's space
521if (!DuplicateHandle(GetCurrentProcess(), shareableHandles[j], hProcess,
522&hDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
523printf("IPC failure: DuplicateHandle failed (%d)\n", GetLastError());
524return -1;
525}
526checkIpcErrors(ipcSendData(handle->hMailslot[i], &hDup, sizeof(hDup)));
527}
528CloseHandle(hProcess);
529}
530return 0;
531}
532
533int ipcRecvShareableHandles(ipcHandle *handle,
534std::vector<ShareableHandle> &shareableHandles) {
535for (int i = 0; i < shareableHandles.size(); i++) {
536checkIpcErrors(
537ipcRecvData(handle, &shareableHandles[i], sizeof(shareableHandles[i])));
538}
539return 0;
540}
541
542int ipcCloseSocket(ipcHandle *handle) {
543for (int i = 0; i < handle->hMailslot.size(); i++) {
544CloseHandle(handle->hMailslot[i]);
545}
546delete handle;
547return 0;
548}
549
550int ipcCloseShareableHandle(ShareableHandle shHandle) {
551CloseHandle(shHandle);
552return 0;
553}
554
555#endif
556