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