Actual source code: send.c
1: #include <petscsys.h>
3: #if defined(PETSC_NEEDS_UTYPE_TYPEDEFS)
4: /* Some systems have inconsistent include files that use but do not
5: ensure that the following definitions are made */
6: typedef unsigned char u_char;
7: typedef unsigned short u_short;
8: typedef unsigned short ushort;
9: typedef unsigned int u_int;
10: typedef unsigned long u_long;
11: #endif
13: #include <errno.h>
14: #include <ctype.h>
15: #if defined(PETSC_HAVE_MACHINE_ENDIAN_H)
16: #include <machine/endian.h>
17: #endif
18: #if defined(PETSC_HAVE_UNISTD_H)
19: #include <unistd.h>
20: #endif
21: #if defined(PETSC_HAVE_SYS_SOCKET_H)
22: #include <sys/socket.h>
23: #endif
24: #if defined(PETSC_HAVE_SYS_WAIT_H)
25: #include <sys/wait.h>
26: #endif
27: #if defined(PETSC_HAVE_NETINET_IN_H)
28: #include <netinet/in.h>
29: #endif
30: #if defined(PETSC_HAVE_NETDB_H)
31: #include <netdb.h>
32: #endif
33: #if defined(PETSC_HAVE_FCNTL_H)
34: #include <fcntl.h>
35: #endif
36: #if defined(PETSC_HAVE_IO_H)
37: #include <io.h>
38: #endif
39: #if defined(PETSC_HAVE_WINSOCK2_H)
40: #include <Winsock2.h>
41: #endif
42: #include <sys/stat.h>
43: #include <../src/sys/classes/viewer/impls/socket/socket.h>
45: #if defined(PETSC_NEED_CLOSE_PROTO)
46: PETSC_EXTERN int close(int);
47: #endif
48: #if defined(PETSC_NEED_SOCKET_PROTO)
49: PETSC_EXTERN int socket(int, int, int);
50: #endif
51: #if defined(PETSC_NEED_SLEEP_PROTO)
52: PETSC_EXTERN int sleep(unsigned);
53: #endif
54: #if defined(PETSC_NEED_CONNECT_PROTO)
55: PETSC_EXTERN int connect(int, struct sockaddr *, int);
56: #endif
58: static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
59: {
60: PetscViewer_Socket *vmatlab = (PetscViewer_Socket *)viewer->data;
62: PetscFunctionBegin;
63: if (vmatlab->port) {
64: int ierr;
66: #if defined(PETSC_HAVE_CLOSESOCKET)
67: ierr = closesocket(vmatlab->port);
68: #else
69: ierr = close(vmatlab->port);
70: #endif
71: PetscCheck(!ierr, PETSC_COMM_SELF, PETSC_ERR_SYS, "System error closing socket");
72: }
73: PetscCall(PetscFree(vmatlab));
74: PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinarySetSkipHeader_C", NULL));
75: PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinaryGetSkipHeader_C", NULL));
76: PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinaryGetFlowControl_C", NULL));
77: PetscFunctionReturn(PETSC_SUCCESS);
78: }
80: /*@C
81: PetscOpenSocket - handles connected to an open port where someone is waiting.
83: Input Parameters:
84: + hostname - for example www.mcs.anl.gov
85: - portnum - for example 80
87: Output Parameter:
88: . t - the socket number
90: Notes:
91: Use close() to close the socket connection
93: Use read() or `PetscHTTPRequest()` to read from the socket
95: Level: advanced
97: .seealso: `PetscSocketListen()`, `PetscSocketEstablish()`, `PetscHTTPRequest()`, `PetscHTTPSConnect()`
98: @*/
99: PetscErrorCode PetscOpenSocket(const char hostname[], int portnum, int *t)
100: {
101: struct sockaddr_in sa;
102: struct hostent *hp;
103: int s = 0;
104: PetscBool flg = PETSC_TRUE;
105: static int refcnt = 0;
107: PetscFunctionBegin;
108: if (!(hp = gethostbyname(hostname))) {
109: perror("SEND: error gethostbyname: ");
110: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error open connection to %s", hostname);
111: }
112: PetscCall(PetscMemzero(&sa, sizeof(sa)));
113: PetscCall(PetscMemcpy(&sa.sin_addr, hp->h_addr_list[0], hp->h_length));
115: sa.sin_family = hp->h_addrtype;
116: sa.sin_port = htons((u_short)portnum);
117: while (flg) {
118: if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) {
119: perror("SEND: error socket");
120: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
121: }
122: if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
123: #if defined(PETSC_HAVE_WSAGETLASTERROR)
124: ierr = WSAGetLastError();
125: if (ierr == WSAEADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n");
126: else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
127: else if (ierr == WSAEISCONN) {
128: (*PetscErrorPrintf)("SEND: socket already connected\n");
129: Sleep((unsigned)1);
130: } else if (ierr == WSAECONNREFUSED) {
131: /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
132: Sleep((unsigned)1);
133: } else {
134: perror(NULL);
135: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
136: }
137: #else
138: if (errno == EADDRINUSE) {
139: PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: address is in use\n");
140: (void)ierr;
141: } else if (errno == EALREADY) {
142: PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
143: (void)ierr;
144: } else if (errno == EISCONN) {
145: PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: socket already connected\n");
146: (void)ierr;
147: sleep((unsigned)1);
148: } else if (errno == ECONNREFUSED) {
149: refcnt++;
150: PetscCheck(refcnt <= 5, PETSC_COMM_SELF, PETSC_ERR_SYS, "Connection refused by remote host %s port %d", hostname, portnum);
151: PetscCall(PetscInfo(NULL, "Connection refused in attaching socket, trying again\n"));
152: sleep((unsigned)1);
153: } else {
154: perror(NULL);
155: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
156: }
157: #endif
158: flg = PETSC_TRUE;
159: #if defined(PETSC_HAVE_CLOSESOCKET)
160: closesocket(s);
161: #else
162: close(s);
163: #endif
164: } else flg = PETSC_FALSE;
165: }
166: *t = s;
167: PetscFunctionReturn(PETSC_SUCCESS);
168: }
170: /*
171: PetscSocketEstablish - starts a listener on a socket
173: Input Parameter:
174: . portnumber - the port to wait at
176: Output Parameter:
177: . ss - the socket to be used with `PetscSocketListen()`
179: Level: advanced
181: .seealso: `PetscSocketListen()`, `PetscOpenSocket()`
182: */
183: static PetscErrorCode PetscSocketEstablish(int portnum, int *ss)
184: {
185: static size_t MAXHOSTNAME = 100;
186: char myname[MAXHOSTNAME + 1];
187: int s;
188: struct sockaddr_in sa;
189: struct hostent *hp;
191: PetscFunctionBegin;
192: PetscCall(PetscGetHostName(myname, sizeof(myname)));
194: PetscCall(PetscMemzero(&sa, sizeof(struct sockaddr_in)));
196: hp = gethostbyname(myname);
197: PetscCheck(hp, PETSC_COMM_SELF, PETSC_ERR_SYS, "Unable to get hostent information from system");
199: sa.sin_family = hp->h_addrtype;
200: sa.sin_port = htons((u_short)portnum);
202: PetscCheck((s = socket(AF_INET, SOCK_STREAM, 0)) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "Error running socket() command");
203: #if defined(PETSC_HAVE_SO_REUSEADDR)
204: {
205: int optval = 1; /* Turn on the option */
206: int ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));
207: PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "setsockopt() failed with error code %d", ret);
208: }
209: #endif
211: while (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
212: #if defined(PETSC_HAVE_WSAGETLASTERROR)
213: ierr = WSAGetLastError();
214: if (ierr != WSAEADDRINUSE) {
215: #else
216: if (errno != EADDRINUSE) {
217: #endif
218: close(s);
219: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "Error from bind()");
220: }
221: }
222: listen(s, 0);
223: *ss = s;
224: PetscFunctionReturn(PETSC_SUCCESS);
225: }
227: /*
228: PetscSocketListen - Listens at a socket created with `PetscSocketEstablish()`
230: Input Parameter:
231: . listenport - obtained with `PetscSocketEstablish()`
233: Output Parameter:
234: . t - pass this to read() to read what is passed to this connection
236: Level: advanced
238: .seealso: `PetscSocketEstablish()`
239: */
240: static PetscErrorCode PetscSocketListen(int listenport, int *t)
241: {
242: struct sockaddr_in isa;
243: #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
244: size_t i;
245: #else
246: int i;
247: #endif
249: PetscFunctionBegin;
250: /* wait for someone to try to connect */
251: i = sizeof(struct sockaddr_in);
252: PetscCheck((*t = accept(listenport, (struct sockaddr *)&isa, (socklen_t *)&i)) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "error from accept()");
253: PetscFunctionReturn(PETSC_SUCCESS);
254: }
256: // "Unknown section 'Environmental Variables'"
257: // PetscClangLinter pragma disable: -fdoc-section-header-unknown
258: /*@C
259: PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.
261: Collective
263: Input Parameters:
264: + comm - the MPI communicator
265: . machine - the machine the server is running on, use `NULL` for the local machine, use "server" to passively wait for
266: a connection from elsewhere
267: - port - the port to connect to, use `PETSC_DEFAULT` for the default
269: Output Parameter:
270: . lab - a context to use when communicating with the server
272: Options Database Keys:
273: For use with `PETSC_VIEWER_SOCKET_WORLD`, `PETSC_VIEWER_SOCKET_SELF`,
274: `PETSC_VIEWER_SOCKET_()` or if
275: `NULL` is passed for machine or PETSC_DEFAULT is passed for port
276: + -viewer_socket_machine <machine> - the machine where the socket is available
277: - -viewer_socket_port <port> - the socket to connect to
279: Environmental variables:
280: + `PETSC_VIEWER_SOCKET_MACHINE` - machine name
281: - `PETSC_VIEWER_SOCKET_PORT` - portnumber
283: Level: intermediate
285: Notes:
286: Most users should employ the following commands to access the
287: MATLAB `PetscViewer`
288: .vb
290: PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
291: MatView(Mat matrix,PetscViewer viewer)
292: .ve
293: or
294: .vb
295: PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
296: VecView(Vec vector,PetscViewer viewer)
297: .ve
299: Currently the only socket client available is MATLAB, PETSc must be configured with --with-matlab for this client. See
300: src/dm/tests/ex12.c and ex12.m for an example of usage.
302: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
303: use `PetscViewerBinaryRead()`, `PetscViewerBinaryWrite()`, `PetscViewerBinarWriteStringArray()`, `PetscViewerBinaryGetDescriptor()`.
305: Use this for communicating with an interactive MATLAB session, see `PETSC_VIEWER_MATLAB_()` for writing output to a
306: .mat file. Use `PetscMatlabEngineCreate()` or `PETSC_MATLAB_ENGINE_()`, `PETSC_MATLAB_ENGINE_SELF`, or `PETSC_MATLAB_ENGINE_WORLD`
307: for communicating with a MATLAB Engine
309: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PETSCVIEWERSOCKET`, `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerSetType()`,
310: `PetscViewerSocketSetConnection()`, `PETSC_VIEWER_SOCKET_`, `PETSC_VIEWER_SOCKET_WORLD`,
311: `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`, `PetscViewerBinaryWriteStringArray()`,
312: `PetscBinaryViewerGetDescriptor()`, `PetscMatlabEngineCreate()`
313: @*/
314: PetscErrorCode PetscViewerSocketOpen(MPI_Comm comm, const char machine[], int port, PetscViewer *lab)
315: {
316: PetscFunctionBegin;
317: PetscCall(PetscViewerCreate(comm, lab));
318: PetscCall(PetscViewerSetType(*lab, PETSCVIEWERSOCKET));
319: PetscCall(PetscViewerSocketSetConnection(*lab, machine, port));
320: PetscFunctionReturn(PETSC_SUCCESS);
321: }
323: static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v, PetscOptionItems *PetscOptionsObject)
324: {
325: PetscInt def = -1;
326: char sdef[256];
327: PetscBool tflg;
329: PetscFunctionBegin;
330: /*
331: These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
332: are listed here for the GUI to display
333: */
334: PetscOptionsHeadBegin(PetscOptionsObject, "Socket PetscViewer Options");
335: PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_PORT", sdef, 16, &tflg));
336: if (tflg) {
337: PetscCall(PetscOptionsStringToInt(sdef, &def));
338: } else def = PETSCSOCKETDEFAULTPORT;
339: PetscCall(PetscOptionsInt("-viewer_socket_port", "Port number to use for socket", "PetscViewerSocketSetConnection", def, NULL, NULL));
341: PetscCall(PetscOptionsString("-viewer_socket_machine", "Machine to use for socket", "PetscViewerSocketSetConnection", sdef, NULL, sizeof(sdef), NULL));
342: PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_MACHINE", sdef, sizeof(sdef), &tflg));
343: if (!tflg) PetscCall(PetscGetHostName(sdef, sizeof(sdef)));
344: PetscOptionsHeadEnd();
345: PetscFunctionReturn(PETSC_SUCCESS);
346: }
348: static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer, PetscBool *skip)
349: {
350: PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data;
352: PetscFunctionBegin;
353: *skip = vsocket->skipheader;
354: PetscFunctionReturn(PETSC_SUCCESS);
355: }
357: static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer, PetscBool skip)
358: {
359: PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data;
361: PetscFunctionBegin;
362: vsocket->skipheader = skip;
363: PetscFunctionReturn(PETSC_SUCCESS);
364: }
366: PETSC_INTERN PetscErrorCode PetscViewerBinaryGetFlowControl_Binary(PetscViewer, PetscInt *);
368: /*MC
369: PETSCVIEWERSOCKET - A viewer that writes to a Unix socket
371: Level: beginner
373: .seealso: [](sec_viewers), `PETSC_VIEWERBINARY`, `PetscViewerSocketOpen()`, `PetscViewerDrawOpen()`, `PETSC_VIEWER_DRAW_()`, `PETSC_VIEWER_DRAW_SELF`, `PETSC_VIEWER_DRAW_WORLD`,
374: `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PETSCVIEWERBINARY`, `PETSCVIEWERDRAW`,
375: `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`,
376: `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
377: M*/
379: PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
380: {
381: PetscViewer_Socket *vmatlab;
383: PetscFunctionBegin;
384: PetscCall(PetscNew(&vmatlab));
385: vmatlab->port = 0;
386: vmatlab->flowcontrol = 256; /* same default as in PetscViewerCreate_Binary() */
387: v->data = (void *)vmatlab;
388: v->ops->destroy = PetscViewerDestroy_Socket;
389: v->ops->flush = NULL;
390: v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
392: /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
393: PetscCall(PetscObjectChangeTypeName((PetscObject)v, PETSCVIEWERBINARY));
394: PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetSkipHeader_C", PetscViewerBinarySetSkipHeader_Socket));
395: PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetSkipHeader_C", PetscViewerBinaryGetSkipHeader_Socket));
396: PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetFlowControl_C", PetscViewerBinaryGetFlowControl_Binary));
397: PetscFunctionReturn(PETSC_SUCCESS);
398: }
400: /*@C
401: PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
402: viewer is to use
404: Logically Collective
406: Input Parameters:
407: + v - viewer to connect
408: . machine - host to connect to, use `NULL` for the local machine,use "server" to passively wait for
409: a connection from elsewhere
410: - port - the port on the machine one is connecting to, use `PETSC_DEFAULT` for default
412: Level: advanced
414: .seealso: [](sec_viewers), `PETSCVIEWERMATLAB`, `PETSCVIEWERSOCKET`, `PetscViewerSocketOpen()`
415: @*/
416: PetscErrorCode PetscViewerSocketSetConnection(PetscViewer v, const char machine[], int port)
417: {
418: PetscMPIInt rank;
419: char mach[256];
420: PetscBool tflg;
421: PetscViewer_Socket *vmatlab;
423: PetscFunctionBegin;
425: if (machine) PetscAssertPointer(machine, 2);
426: vmatlab = (PetscViewer_Socket *)v->data;
428: if (port <= 0) {
429: char portn[16];
430: PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_PORT", portn, 16, &tflg));
431: if (tflg) {
432: PetscInt pport;
433: PetscCall(PetscOptionsStringToInt(portn, &pport));
434: port = (int)pport;
435: } else port = PETSCSOCKETDEFAULTPORT;
436: }
437: if (!machine) {
438: PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_MACHINE", mach, sizeof(mach), &tflg));
439: if (!tflg) PetscCall(PetscGetHostName(mach, sizeof(mach)));
440: } else {
441: PetscCall(PetscStrncpy(mach, machine, sizeof(mach)));
442: }
444: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)v), &rank));
445: if (rank == 0) {
446: PetscCall(PetscStrcmp(mach, "server", &tflg));
447: if (tflg) {
448: int listenport = 0;
450: PetscCall(PetscInfo(v, "Waiting for connection from socket process on port %d\n", port));
451: PetscCall(PetscSocketEstablish(port, &listenport));
452: PetscCall(PetscSocketListen(listenport, &vmatlab->port));
453: close(listenport);
454: } else {
455: PetscCall(PetscInfo(v, "Connecting to socket process on port %d machine %s\n", port, mach));
456: PetscCall(PetscOpenSocket(mach, port, &vmatlab->port));
457: }
458: }
459: PetscFunctionReturn(PETSC_SUCCESS);
460: }
462: /*
463: The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
464: is attached to a communicator, in this case the attribute is a PetscViewer.
465: */
466: PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
468: /*@C
469: PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
471: Collective
473: Input Parameter:
474: . comm - the MPI communicator to share the `PETSCVIEWERSOCKET` `PetscViewer`
476: Level: intermediate
478: Options Database Keys:
479: For use with the default `PETSC_VIEWER_SOCKET_WORLD` or if
480: `NULL` is passed for machine or `PETSC_DEFAULT` is passed for port
481: + -viewer_socket_machine <machine> - machine to connect to
482: - -viewer_socket_port <port> - port to connect to
484: Environmental variables:
485: + `PETSC_VIEWER_SOCKET_PORT` - portnumber
486: - `PETSC_VIEWER_SOCKET_MACHINE` - machine name
488: Notes:
489: This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it
491: Unlike almost all other PETSc routines, `PETSC_VIEWER_SOCKET_()` does not return
492: an error code, it returns NULL if it fails. The `PETSCVIEWERSOCKET` `PetscViewer` is usually used in the form
493: $ XXXView(XXX object, PETSC_VIEWER_SOCKET_(comm));
495: Currently the only socket client available is MATLAB. See
496: src/dm/tests/ex12.c and ex12.m for an example of usage.
498: Connects to a waiting socket and stays connected until `PetscViewerDestroy()` is called.
500: Use this for communicating with an interactive MATLAB session, see `PETSC_VIEWER_MATLAB_()` for writing output to a
501: .mat file. Use `PetscMatlabEngineCreate()` or `PETSC_MATLAB_ENGINE_()`, `PETSC_MATLAB_ENGINE_SELF`, or `PETSC_MATLAB_ENGINE_WORLD`
502: for communicating with a MATLAB Engine
504: .seealso: [](sec_viewers), `PETSCVIEWERMATLAB`, `PETSCVIEWERSOCKET`, `PETSC_VIEWER_SOCKET_WORLD`, `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerSocketOpen()`, `PetscViewerCreate()`,
505: `PetscViewerSocketSetConnection()`, `PetscViewerDestroy()`, `PETSC_VIEWER_SOCKET_()`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`,
506: `PetscViewerBinaryWriteStringArray()`, `PetscViewerBinaryGetDescriptor()`, `PETSC_VIEWER_MATLAB_()`
507: @*/
508: PetscViewer PETSC_VIEWER_SOCKET_(MPI_Comm comm)
509: {
510: PetscErrorCode ierr;
511: PetscMPIInt mpi_ierr;
512: PetscBool flg;
513: PetscViewer viewer;
514: MPI_Comm ncomm;
516: PetscFunctionBegin;
517: ierr = PetscCommDuplicate(comm, &ncomm, NULL);
518: if (ierr) {
519: ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
520: PetscFunctionReturn(NULL);
521: }
522: if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
523: mpi_ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Socket_keyval, NULL);
524: if (mpi_ierr) {
525: ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
526: PetscFunctionReturn(NULL);
527: }
528: }
529: mpi_ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Socket_keyval, (void **)&viewer, (int *)&flg);
530: if (mpi_ierr) {
531: ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
532: PetscFunctionReturn(NULL);
533: }
534: if (!flg) { /* PetscViewer not yet created */
535: ierr = PetscViewerSocketOpen(ncomm, NULL, 0, &viewer);
536: ((PetscObject)viewer)->persistent = PETSC_TRUE;
537: if (ierr) {
538: ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
539: PetscFunctionReturn(NULL);
540: }
541: ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
542: if (ierr) {
543: ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
544: PetscFunctionReturn(NULL);
545: }
546: mpi_ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Socket_keyval, (void *)viewer);
547: if (mpi_ierr) {
548: ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
549: PetscFunctionReturn(NULL);
550: }
551: }
552: ierr = PetscCommDestroy(&ncomm);
553: if (ierr) {
554: ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
555: PetscFunctionReturn(NULL);
556: }
557: PetscFunctionReturn(viewer);
558: }