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