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