Path: blob/master/src/jdk.jdi/share/native/libdt_shmem/shmemBase.c
41149 views
/*1* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24#include <stdio.h>25#include <string.h>26#include <errno.h>27#include <stdlib.h>2829#include "sysShmem.h"30#include "shmemBase.h"31#include "jdwpTransport.h" /* for Packet, TransportCallback */3233#if defined(_WIN32)34#define PRId64 "I64d"35#endif3637#define MIN(x,y) ((x)<(y)?(x):(y))3839/*40* This is the base shared memory transport implementation that is used41* by both front-end transports (through com.sun.tools.jdi) and42* back-end transports (through JDWP_OnLoad and the function tables43* it requires). It supports multiple connections for the benefit of the44* front-end client; the back end interface assumes only a single connection.45*/4647#define MAX_IPC_PREFIX 50 /* user-specified or generated name for */48/* shared memory seg and prefix for other IPC */49#define MAX_IPC_SUFFIX 25 /* suffix to shmem name for other IPC names */50#define MAX_IPC_NAME (MAX_IPC_PREFIX + MAX_IPC_SUFFIX)5152#define MAX_GENERATION_RETRIES 2053#define SHARED_BUFFER_SIZE 50005455#define CHECK_ERROR(expr) do { \56jint error = (expr); \57if (error != SYS_OK) { \58setLastError(error); \59return error; \60} \61} while (0)6263#define ENTER_CONNECTION(connection) \64do { \65InterlockedIncrement(&connection->refcount); \66if (IS_STATE_CLOSED(connection->state)) { \67setLastErrorMsg("stream closed"); \68InterlockedDecrement(&connection->refcount); \69return SYS_ERR; \70} \71} while (0)7273#define LEAVE_CONNECTION(connection) \74do { \75InterlockedDecrement(&connection->refcount); \76} while (0)7778/*79* The following assertions should hold anytime the stream's mutex is not held80*/81#define STREAM_INVARIANT(stream) \82do { \83SHMEM_ASSERT((stream->shared->readOffset < SHARED_BUFFER_SIZE) \84&& (stream->shared->readOffset >= 0)); \85SHMEM_ASSERT((stream->shared->writeOffset < SHARED_BUFFER_SIZE) \86&& (stream->shared->writeOffset >= 0)); \87} while (0)8889/*90* Transports are duplex, so carve the shared memory into "streams",91* one used to send from client to server, the other vice versa.92*/93typedef struct SharedMemoryListener {94char mutexName[MAX_IPC_NAME];95char acceptEventName[MAX_IPC_NAME];96char attachEventName[MAX_IPC_NAME];97jboolean isListening;98jboolean isAccepted;99jlong acceptingPID;100jlong attachingPID;101} SharedListener;102103typedef struct SharedMemoryTransport {104char name[MAX_IPC_PREFIX];105sys_ipmutex_t mutex;106sys_event_t acceptEvent;107sys_event_t attachEvent;108sys_shmem_t sharedMemory;109SharedListener *shared;110} SharedMemoryTransport;111112/*113* Access must be syncronized. Holds one shared114* memory buffer and its state.115*/116typedef struct SharedStream {117char mutexName[MAX_IPC_NAME];118char hasDataEventName[MAX_IPC_NAME];119char hasSpaceEventName[MAX_IPC_NAME];120int readOffset;121int writeOffset;122jboolean isFull;123jbyte buffer[SHARED_BUFFER_SIZE];124} SharedStream;125126/*127* The two shared streams: client to server and128* server to client.129*/130typedef struct SharedMemory {131SharedStream toClient;132SharedStream toServer;133} SharedMemory;134135/*136* Local (to process) access to the shared memory137* stream. access to hasData and hasSpace synchronized138* by OS.139*/140typedef struct Stream {141sys_ipmutex_t mutex;142sys_event_t hasData;143sys_event_t hasSpace;144SharedStream *shared;145jint state;146} Stream;147148/*149* Values for Stream.state field above.150*/151#define STATE_CLOSED 0xDEAD152#define STATE_OPEN (STATE_CLOSED -1)153/*154* State checking macro. We compare against the STATE_OPEN value so155* that STATE_CLOSED and any other value will be considered closed.156* This catches a freed Stream as long as the memory page is still157* valid. If the memory page is gone, then there is little that we158* can do.159*/160#define IS_STATE_CLOSED(state) (state != STATE_OPEN)161162163typedef struct SharedMemoryConnection {164char name[MAX_IPC_NAME];165SharedMemory *shared;166sys_shmem_t sharedMemory;167Stream incoming;168Stream outgoing;169sys_process_t otherProcess;170sys_event_t shutdown; /* signalled to indicate shutdown */171volatile DWORD32 refcount;172jint state;173} SharedMemoryConnection;174175static jdwpTransportCallback *callback;176static JavaVM *jvm;177static int tlsIndex;178179typedef jint (*CreateFunc)(char *name, void *arg);180181/*182* Set the per-thread error message (if not already set)183*/184static void185setLastErrorMsg(char *newmsg) {186char *msg;187188msg = (char *)sysTlsGet(tlsIndex);189if (msg == NULL) {190msg = (*callback->alloc)((int)strlen(newmsg)+1);191if (msg != NULL) {192strcpy(msg, newmsg);193}194sysTlsPut(tlsIndex, (void *)msg);195}196}197198/*199* Clear last per-thread error message200*/201static void202clearLastError() {203char* msg = (char *)sysTlsGet(tlsIndex);204if (msg != NULL) {205(*callback->free)(msg);206sysTlsPut(tlsIndex, NULL);207}208}209210/*211* Set the per-thread error message to the textual representation212* of the last system error (if not already set)213*/214static void215setLastError(jint error) {216char buf[128];217218switch (error) {219case SYS_OK : return; /* no-op */220case SYS_DIED : strcpy(buf, "Other process terminated"); break;221case SYS_TIMEOUT : strcpy(buf, "Timed out"); break;222default : sysGetLastError(buf, sizeof(buf));223}224setLastErrorMsg(buf);225}226227jint228shmemBase_initialize(JavaVM *vm, jdwpTransportCallback *cbPtr)229{230jvm = vm;231callback = cbPtr;232tlsIndex = sysTlsAlloc();233return SYS_OK;234}235236static jint237createWithGeneratedName(char *prefix, char *nameBuffer, CreateFunc func, void *arg)238{239jint error;240jint i = 0;241242do {243strcpy(nameBuffer, prefix);244if (i > 0) {245char buf[10];246sprintf(buf, ".%d", i+1);247strcat(nameBuffer, buf);248}249error = func(nameBuffer, arg);250i++;251} while ((error == SYS_INUSE) && (i < MAX_GENERATION_RETRIES));252253if (error != SYS_OK) {254setLastError(error);255}256257return error;258}259260typedef struct SharedMemoryArg {261jint size;262sys_shmem_t memory;263void *start;264} SharedMemoryArg;265266static jint267createSharedMem(char *name, void *ptr)268{269SharedMemoryArg *arg = ptr;270return sysSharedMemCreate(name, arg->size, &arg->memory, &arg->start);271}272273static jint274createMutex(char *name, void *arg)275{276sys_ipmutex_t *retArg = arg;277return sysIPMutexCreate(name, retArg);278}279280/*281* Creates named or unnamed event that is automatically reset282* (in other words, no need to reset event after it has signalled283* a thread).284*/285static jint286createEvent(char *name, void *arg)287{288sys_event_t *retArg = arg;289return sysEventCreate(name, retArg, JNI_FALSE);290}291292#define ADD_OFFSET(o1, o2) ((o1 + o2) % SHARED_BUFFER_SIZE)293#define FULL(stream) (stream->shared->isFull)294#define EMPTY(stream) ((stream->shared->writeOffset == stream->shared->readOffset) \295&& !stream->shared->isFull)296297static jint298leaveMutex(Stream *stream)299{300return sysIPMutexExit(stream->mutex);301}302303/* enter the stream's mutex and (optionally) check for a closed stream */304static jint305enterMutex(Stream *stream, sys_event_t event)306{307jint ret = sysIPMutexEnter(stream->mutex, event);308if (ret != SYS_OK) {309if (IS_STATE_CLOSED(stream->state)) {310setLastErrorMsg("stream closed");311}312return ret;313}314if (IS_STATE_CLOSED(stream->state)) {315setLastErrorMsg("stream closed");316(void)leaveMutex(stream);317return SYS_ERR;318}319return SYS_OK;320}321322/*323* Enter/exit with stream mutex held.324* On error, does not hold the stream mutex.325*/326static jint327waitForSpace(SharedMemoryConnection *connection, Stream *stream)328{329jint error = SYS_OK;330331/* Assumes mutex is held on call */332while ((error == SYS_OK) && FULL(stream)) {333CHECK_ERROR(leaveMutex(stream));334error = sysEventWait(connection->otherProcess, stream->hasSpace, 0);335if (error == SYS_OK) {336CHECK_ERROR(enterMutex(stream, connection->shutdown));337} else {338setLastError(error);339}340}341return error;342}343344static jint345signalSpace(Stream *stream)346{347return sysEventSignal(stream->hasSpace);348}349350/*351* Enter/exit with stream mutex held.352* On error, does not hold the stream mutex.353*/354static jint355waitForData(SharedMemoryConnection *connection, Stream *stream)356{357jint error = SYS_OK;358359/* Assumes mutex is held on call */360while ((error == SYS_OK) && EMPTY(stream)) {361CHECK_ERROR(leaveMutex(stream));362error = sysEventWait(connection->otherProcess, stream->hasData, 0);363if (error == SYS_OK) {364CHECK_ERROR(enterMutex(stream, connection->shutdown));365} else {366setLastError(error);367}368}369return error;370}371372static jint373signalData(Stream *stream)374{375return sysEventSignal(stream->hasData);376}377378379static jint380closeStream(Stream *stream, jboolean linger, volatile DWORD32 *refcount)381{382/*383* Lock stream during close - ignore shutdown event as we are384* closing down and shutdown should be signalled.385*/386CHECK_ERROR(enterMutex(stream, NULL));387388/* mark the stream as closed */389stream->state = STATE_CLOSED;390/* wake up waitForData() if it is in sysEventWait() */391sysEventSignal(stream->hasData);392/* wake up waitForSpace() if it is in sysEventWait() */393sysEventSignal(stream->hasSpace);394395/*396* If linger requested then give the stream a few seconds to397* drain before closing it.398*/399if (linger) {400int attempts = 10;401while (!EMPTY(stream) && attempts>0) {402CHECK_ERROR(leaveMutex(stream));403sysSleep(200);404CHECK_ERROR(enterMutex(stream, NULL));405attempts--;406}407}408409CHECK_ERROR(leaveMutex(stream));410411/* Attempt to close resources */412int attempts = 10;413while (attempts > 0) {414if (*refcount == 0) {415sysEventClose(stream->hasData);416sysEventClose(stream->hasSpace);417sysIPMutexClose(stream->mutex);418return SYS_OK;419}420sysSleep(200);421attempts--;422}423return SYS_ERR;424}425426/*427* Server creates stream.428*/429static int430createStream(char *name, Stream *stream)431{432jint error;433char objectName[MAX_IPC_NAME];434435sprintf(objectName, "%s.mutex", name);436error = createWithGeneratedName(objectName, stream->shared->mutexName,437createMutex, &stream->mutex);438if (error != SYS_OK) {439return error;440}441442sprintf(objectName, "%s.hasData", name);443error = createWithGeneratedName(objectName, stream->shared->hasDataEventName,444createEvent, &stream->hasData);445if (error != SYS_OK) {446sysIPMutexClose(stream->mutex);447return error;448}449450sprintf(objectName, "%s.hasSpace", name);451error = createWithGeneratedName(objectName, stream->shared->hasSpaceEventName,452createEvent, &stream->hasSpace);453if (error != SYS_OK) {454sysIPMutexClose(stream->mutex);455sysEventClose(stream->hasData);456return error;457}458459stream->shared->readOffset = 0;460stream->shared->writeOffset = 0;461stream->shared->isFull = JNI_FALSE;462stream->state = STATE_OPEN;463return SYS_OK;464}465466467/*468* Initialization for the stream opened by the other process469*/470static int471openStream(Stream *stream)472{473jint error;474475CHECK_ERROR(sysIPMutexOpen(stream->shared->mutexName, &stream->mutex));476477error = sysEventOpen(stream->shared->hasDataEventName,478&stream->hasData);479if (error != SYS_OK) {480setLastError(error);481sysIPMutexClose(stream->mutex);482return error;483}484485error = sysEventOpen(stream->shared->hasSpaceEventName,486&stream->hasSpace);487if (error != SYS_OK) {488setLastError(error);489sysIPMutexClose(stream->mutex);490sysEventClose(stream->hasData);491return error;492}493494stream->state = STATE_OPEN;495496return SYS_OK;497}498499/********************************************************************/500501static SharedMemoryConnection *502allocConnection(void)503{504/*505* TO DO: Track all allocated connections for clean shutdown?506*/507SharedMemoryConnection *conn = (*callback->alloc)(sizeof(SharedMemoryConnection));508if (conn != NULL) {509memset(conn, 0, sizeof(SharedMemoryConnection));510}511conn->state = STATE_OPEN;512return conn;513}514515static void516freeConnection(SharedMemoryConnection *connection)517{518(*callback->free)(connection);519}520521static void522closeConnection(SharedMemoryConnection *connection)523{524/* mark the connection as closed */525connection->state = STATE_CLOSED;526527/*528* Signal all threads accessing this connection that we are529* shutting down.530*/531if (connection->shutdown) {532sysEventSignal(connection->shutdown);533}534535Stream * stream = &connection->outgoing;536if (stream->state == STATE_OPEN) {537(void)closeStream(stream, JNI_TRUE, &connection->refcount);538}539stream = &connection->incoming;540if (stream->state == STATE_OPEN) {541(void)closeStream(stream, JNI_FALSE, &connection->refcount);542}543544if (connection->refcount == 0) {545if (connection->sharedMemory) {546sysSharedMemClose(connection->sharedMemory, connection->shared);547}548if (connection->otherProcess) {549sysProcessClose(connection->otherProcess);550}551if (connection->shutdown) {552sysEventClose(connection->shutdown);553}554}555}556557558/*559* For client: connect to the shared memory. Open incoming and560* outgoing streams.561*/562static jint563openConnection(SharedMemoryTransport *transport, jlong otherPID,564SharedMemoryConnection **connectionPtr)565{566jint error;567568SharedMemoryConnection *connection = allocConnection();569if (connection == NULL) {570return SYS_NOMEM;571}572573sprintf(connection->name, "%s.%" PRId64, transport->name, sysProcessGetID());574error = sysSharedMemOpen(connection->name, &connection->sharedMemory,575&connection->shared);576if (error != SYS_OK) {577freeConnection(connection);578return error;579}580581/* This process is the client */582connection->incoming.shared = &connection->shared->toClient;583connection->outgoing.shared = &connection->shared->toServer;584585error = openStream(&connection->incoming);586if (error != SYS_OK) {587closeConnection(connection);588freeConnection(connection);589return error;590}591592error = openStream(&connection->outgoing);593if (error != SYS_OK) {594closeConnection(connection);595freeConnection(connection);596return error;597}598599error = sysProcessOpen(otherPID, &connection->otherProcess);600if (error != SYS_OK) {601setLastError(error);602closeConnection(connection);603freeConnection(connection);604return error;605}606607/*608* Create an event that signals that the connection is shutting609* down. The event is unnamed as it's process local, and is610* manually reset (so that signalling the event will signal611* all threads waiting on it).612*/613error = sysEventCreate(NULL, &connection->shutdown, JNI_TRUE);614if (error != SYS_OK) {615setLastError(error);616closeConnection(connection);617freeConnection(connection);618return error;619}620621*connectionPtr = connection;622return SYS_OK;623}624625/*626* For server: create the shared memory. Create incoming and627* outgoing streams.628*/629static jint630createConnection(SharedMemoryTransport *transport, jlong otherPID,631SharedMemoryConnection **connectionPtr)632{633jint error;634char streamName[MAX_IPC_NAME];635636SharedMemoryConnection *connection = allocConnection();637if (connection == NULL) {638return SYS_NOMEM;639}640641sprintf(connection->name, "%s.%" PRId64, transport->name, otherPID);642error = sysSharedMemCreate(connection->name, sizeof(SharedMemory),643&connection->sharedMemory, &connection->shared);644if (error != SYS_OK) {645freeConnection(connection);646return error;647}648649memset(connection->shared, 0, sizeof(SharedMemory));650651/* This process is the server */652connection->incoming.shared = &connection->shared->toServer;653connection->outgoing.shared = &connection->shared->toClient;654655strcpy(streamName, connection->name);656strcat(streamName, ".ctos");657error = createStream(streamName, &connection->incoming);658if (error != SYS_OK) {659closeConnection(connection);660freeConnection(connection);661return error;662}663664strcpy(streamName, connection->name);665strcat(streamName, ".stoc");666error = createStream(streamName, &connection->outgoing);667if (error != SYS_OK) {668closeConnection(connection);669freeConnection(connection);670return error;671}672673error = sysProcessOpen(otherPID, &connection->otherProcess);674if (error != SYS_OK) {675setLastError(error);676closeConnection(connection);677freeConnection(connection);678return error;679}680681/*682* Create an event that signals that the connection is shutting683* down. The event is unnamed as it's process local, and is684* manually reset (so that a signalling the event will signal685* all threads waiting on it).686*/687error = sysEventCreate(NULL, &connection->shutdown, JNI_TRUE);688if (error != SYS_OK) {689setLastError(error);690closeConnection(connection);691freeConnection(connection);692return error;693}694695*connectionPtr = connection;696return SYS_OK;697}698699/********************************************************************/700701static SharedMemoryTransport *702allocTransport(void)703{704/*705* TO DO: Track all allocated transports for clean shutdown?706*/707return (*callback->alloc)(sizeof(SharedMemoryTransport));708}709710static void711freeTransport(SharedMemoryTransport *transport)712{713(*callback->free)(transport);714}715716static void717closeTransport(SharedMemoryTransport *transport)718{719sysIPMutexClose(transport->mutex);720sysEventClose(transport->acceptEvent);721sysEventClose(transport->attachEvent);722sysSharedMemClose(transport->sharedMemory, transport->shared);723freeTransport(transport);724}725726static int727openTransport(const char *address, SharedMemoryTransport **transportPtr)728{729jint error;730SharedMemoryTransport *transport;731732transport = allocTransport();733if (transport == NULL) {734return SYS_NOMEM;735}736memset(transport, 0, sizeof(*transport));737738if (strlen(address) >= MAX_IPC_PREFIX) {739char buf[128];740sprintf(buf, "Error: address strings longer than %d characters are invalid\n", MAX_IPC_PREFIX);741setLastErrorMsg(buf);742closeTransport(transport);743return SYS_ERR;744}745746error = sysSharedMemOpen(address, &transport->sharedMemory, &transport->shared);747if (error != SYS_OK) {748setLastError(error);749closeTransport(transport);750return error;751}752strcpy(transport->name, address);753754error = sysIPMutexOpen(transport->shared->mutexName, &transport->mutex);755if (error != SYS_OK) {756setLastError(error);757closeTransport(transport);758return error;759}760761error = sysEventOpen(transport->shared->acceptEventName,762&transport->acceptEvent);763if (error != SYS_OK) {764setLastError(error);765closeTransport(transport);766return error;767}768769error = sysEventOpen(transport->shared->attachEventName,770&transport->attachEvent);771if (error != SYS_OK) {772setLastError(error);773closeTransport(transport);774return error;775}776777*transportPtr = transport;778return SYS_OK;779}780781static jint782createTransport(const char *address, SharedMemoryTransport **transportPtr)783{784SharedMemoryTransport *transport;785jint error;786char objectName[MAX_IPC_NAME];787788transport = allocTransport();789if (transport == NULL) {790return SYS_NOMEM;791}792memset(transport, 0, sizeof(*transport));793794if ((address == NULL) || (address[0] == '\0')) {795SharedMemoryArg arg;796arg.size = sizeof(SharedListener);797error = createWithGeneratedName("javadebug", transport->name,798createSharedMem, &arg);799transport->shared = arg.start;800transport->sharedMemory = arg.memory;801} else {802if (strlen(address) >= MAX_IPC_PREFIX) {803char buf[128];804sprintf(buf, "Error: address strings longer than %d characters are invalid\n", MAX_IPC_PREFIX);805setLastErrorMsg(buf);806closeTransport(transport);807return SYS_ERR;808}809strcpy(transport->name, address);810error = sysSharedMemCreate(address, sizeof(SharedListener),811&transport->sharedMemory, &transport->shared);812}813if (error != SYS_OK) {814setLastError(error);815closeTransport(transport);816return error;817}818819memset(transport->shared, 0, sizeof(SharedListener));820transport->shared->acceptingPID = sysProcessGetID();821822sprintf(objectName, "%s.mutex", transport->name);823error = createWithGeneratedName(objectName, transport->shared->mutexName,824createMutex, &transport->mutex);825if (error != SYS_OK) {826closeTransport(transport);827return error;828}829830sprintf(objectName, "%s.accept", transport->name);831error = createWithGeneratedName(objectName, transport->shared->acceptEventName,832createEvent, &transport->acceptEvent);833if (error != SYS_OK) {834closeTransport(transport);835return error;836}837838sprintf(objectName, "%s.attach", transport->name);839error = createWithGeneratedName(objectName, transport->shared->attachEventName,840createEvent, &transport->attachEvent);841if (error != SYS_OK) {842closeTransport(transport);843return error;844}845846*transportPtr = transport;847return SYS_OK;848}849850851jint852shmemBase_listen(const char *address, SharedMemoryTransport **transportPtr)853{854int error;855856clearLastError();857858error = createTransport(address, transportPtr);859if (error == SYS_OK) {860(*transportPtr)->shared->isListening = JNI_TRUE;861}862return error;863}864865866jint867shmemBase_accept(SharedMemoryTransport *transport,868long timeout,869SharedMemoryConnection **connectionPtr)870{871jint error;872SharedMemoryConnection *connection;873874clearLastError();875876CHECK_ERROR(sysEventWait(NULL, transport->attachEvent, timeout));877878error = createConnection(transport, transport->shared->attachingPID,879&connection);880if (error != SYS_OK) {881/*882* Reject the attacher883*/884transport->shared->isAccepted = JNI_FALSE;885sysEventSignal(transport->acceptEvent);886887return error;888}889890transport->shared->isAccepted = JNI_TRUE;891error = sysEventSignal(transport->acceptEvent);892if (error != SYS_OK) {893/*894* No real point trying to reject it.895*/896closeConnection(connection);897freeConnection(connection);898return error;899}900901*connectionPtr = connection;902return SYS_OK;903}904905static jint906doAttach(SharedMemoryTransport *transport, long timeout)907{908transport->shared->attachingPID = sysProcessGetID();909CHECK_ERROR(sysEventSignal(transport->attachEvent));910CHECK_ERROR(sysEventWait(NULL, transport->acceptEvent, timeout));911return SYS_OK;912}913914jint915shmemBase_attach(const char *addressString, long timeout, SharedMemoryConnection **connectionPtr)916{917int error;918SharedMemoryTransport *transport;919jlong acceptingPID;920921clearLastError();922923error = openTransport(addressString, &transport);924if (error != SYS_OK) {925return error;926}927928/* lock transport - no additional event to wait on as no connection yet */929error = sysIPMutexEnter(transport->mutex, NULL);930if (error != SYS_OK) {931setLastError(error);932closeTransport(transport);933return error;934}935936if (transport->shared->isListening) {937error = doAttach(transport, timeout);938if (error == SYS_OK) {939acceptingPID = transport->shared->acceptingPID;940}941} else {942/* Not listening: error */943error = SYS_ERR;944}945946sysIPMutexExit(transport->mutex);947if (error != SYS_OK) {948closeTransport(transport);949return error;950}951952error = openConnection(transport, acceptingPID, connectionPtr);953954closeTransport(transport);955956return error;957}958959960961962void963shmemBase_closeConnection(SharedMemoryConnection *connection)964{965clearLastError();966closeConnection(connection);967/*968* Ideally we should free the connection structure. However,969* since the connection has already being published, other970* threads may still be accessing it. In particular, refcount971* and state fields could be accessed at any time even after972* closing the connection. On Win32 this means we leak 140973* bytes. This memory will be reclaimed at process exit.974*975* In general reference counting should exist externally to976* the object being managed so that it can be freed. If we977* want to free SharedMemoryConnection, one alternative could978* be to define a new struct X and move all those fields there979* except refcount and state. We would have a pointer to a980* dynamically allocated X from SharedMemoryConnection. Then981* if refcount is 0 we could also free X. This would leak982* 12 bytes instead of 140.983*984* freeConnection(connection);985*986*/987}988989void990shmemBase_closeTransport(SharedMemoryTransport *transport)991{992clearLastError();993closeTransport(transport);994}995996static jint997shmemBase_sendByte_internal(SharedMemoryConnection *connection, jbyte data)998{999Stream *stream = &connection->outgoing;1000SharedStream *shared = stream->shared;1001int offset;10021003clearLastError();10041005CHECK_ERROR(enterMutex(stream, connection->shutdown));1006CHECK_ERROR(waitForSpace(connection, stream));1007SHMEM_ASSERT(!FULL(stream));1008offset = shared->writeOffset;1009shared->buffer[offset] = data;1010shared->writeOffset = ADD_OFFSET(offset, 1);1011shared->isFull = (shared->readOffset == shared->writeOffset);10121013STREAM_INVARIANT(stream);1014CHECK_ERROR(leaveMutex(stream));10151016CHECK_ERROR(signalData(stream));10171018return SYS_OK;1019}10201021jint1022shmemBase_sendByte(SharedMemoryConnection *connection, jbyte data)1023{1024ENTER_CONNECTION(connection);1025jint rc = shmemBase_sendByte_internal(connection, data);1026LEAVE_CONNECTION(connection);1027return rc;1028}10291030static jint1031shmemBase_receiveByte_internal(SharedMemoryConnection *connection, jbyte *data)1032{1033Stream *stream = &connection->incoming;1034SharedStream *shared = stream->shared;1035int offset;10361037clearLastError();10381039CHECK_ERROR(enterMutex(stream, connection->shutdown));1040CHECK_ERROR(waitForData(connection, stream));1041SHMEM_ASSERT(!EMPTY(stream));1042offset = shared->readOffset;1043*data = shared->buffer[offset];1044shared->readOffset = ADD_OFFSET(offset, 1);1045shared->isFull = JNI_FALSE;10461047STREAM_INVARIANT(stream);1048CHECK_ERROR(leaveMutex(stream));10491050CHECK_ERROR(signalSpace(stream));10511052return SYS_OK;1053}10541055jint1056shmemBase_receiveByte(SharedMemoryConnection *connection, jbyte *data)1057{1058ENTER_CONNECTION(connection);1059jint rc = shmemBase_receiveByte_internal(connection, data);1060LEAVE_CONNECTION(connection);1061return rc;1062}10631064static jint1065sendBytes(SharedMemoryConnection *connection, const void *bytes, jint length)1066{1067Stream *stream = &connection->outgoing;1068SharedStream *shared = stream->shared;1069jint fragmentStart;1070jint fragmentLength;1071jint index = 0;1072jint maxLength;10731074clearLastError();10751076CHECK_ERROR(enterMutex(stream, connection->shutdown));1077while (index < length) {1078CHECK_ERROR(waitForSpace(connection, stream));1079SHMEM_ASSERT(!FULL(stream));10801081fragmentStart = shared->writeOffset;10821083if (fragmentStart < shared->readOffset) {1084maxLength = shared->readOffset - fragmentStart;1085} else {1086maxLength = SHARED_BUFFER_SIZE - fragmentStart;1087}1088fragmentLength = MIN(maxLength, length - index);1089memcpy(shared->buffer + fragmentStart, (jbyte *)bytes + index, fragmentLength);1090shared->writeOffset = ADD_OFFSET(fragmentStart, fragmentLength);1091index += fragmentLength;10921093shared->isFull = (shared->readOffset == shared->writeOffset);10941095STREAM_INVARIANT(stream);1096CHECK_ERROR(signalData(stream));10971098}1099CHECK_ERROR(leaveMutex(stream));11001101return SYS_OK;1102}110311041105/*1106* Send packet header followed by data.1107*/1108static jint1109shmemBase_sendPacket_internal(SharedMemoryConnection *connection, const jdwpPacket *packet)1110{1111jint data_length;11121113clearLastError();11141115CHECK_ERROR(sendBytes(connection, &packet->type.cmd.id, sizeof(jint)));1116CHECK_ERROR(sendBytes(connection, &packet->type.cmd.flags, sizeof(jbyte)));11171118if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {1119CHECK_ERROR(sendBytes(connection, &packet->type.reply.errorCode, sizeof(jshort)));1120} else {1121CHECK_ERROR(sendBytes(connection, &packet->type.cmd.cmdSet, sizeof(jbyte)));1122CHECK_ERROR(sendBytes(connection, &packet->type.cmd.cmd, sizeof(jbyte)));1123}11241125data_length = packet->type.cmd.len - JDWP_HEADER_SIZE;1126SHMEM_GUARANTEE(data_length >= 0);1127CHECK_ERROR(sendBytes(connection, &data_length, sizeof(jint)));11281129if (data_length > 0) {1130CHECK_ERROR(sendBytes(connection, packet->type.cmd.data, data_length));1131}11321133return SYS_OK;1134}11351136jint1137shmemBase_sendPacket(SharedMemoryConnection *connection, const jdwpPacket *packet)1138{1139ENTER_CONNECTION(connection);1140jint rc = shmemBase_sendPacket_internal(connection, packet);1141LEAVE_CONNECTION(connection);1142return rc;1143}11441145static jint1146receiveBytes(SharedMemoryConnection *connection, void *bytes, jint length)1147{1148Stream *stream = &connection->incoming;1149SharedStream *shared = stream->shared;1150jint fragmentStart;1151jint fragmentLength;1152jint index = 0;1153jint maxLength;11541155clearLastError();11561157CHECK_ERROR(enterMutex(stream, connection->shutdown));1158while (index < length) {1159CHECK_ERROR(waitForData(connection, stream));1160SHMEM_ASSERT(!EMPTY(stream));11611162fragmentStart = shared->readOffset;1163if (fragmentStart < shared->writeOffset) {1164maxLength = shared->writeOffset - fragmentStart;1165} else {1166maxLength = SHARED_BUFFER_SIZE - fragmentStart;1167}1168fragmentLength = MIN(maxLength, length - index);1169memcpy((jbyte *)bytes + index, shared->buffer + fragmentStart, fragmentLength);1170shared->readOffset = ADD_OFFSET(fragmentStart, fragmentLength);1171index += fragmentLength;11721173shared->isFull = JNI_FALSE;11741175STREAM_INVARIANT(stream);1176CHECK_ERROR(signalSpace(stream));1177}1178CHECK_ERROR(leaveMutex(stream));11791180return SYS_OK;1181}11821183/*1184* Read packet header and insert into packet structure.1185* Allocate space for the data and fill it in.1186*/1187static jint1188shmemBase_receivePacket_internal(SharedMemoryConnection *connection, jdwpPacket *packet)1189{1190jint data_length;1191jint error;11921193clearLastError();11941195CHECK_ERROR(receiveBytes(connection, &packet->type.cmd.id, sizeof(jint)));1196CHECK_ERROR(receiveBytes(connection, &packet->type.cmd.flags, sizeof(jbyte)));11971198if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {1199CHECK_ERROR(receiveBytes(connection, &packet->type.reply.errorCode, sizeof(jshort)));1200} else {1201CHECK_ERROR(receiveBytes(connection, &packet->type.cmd.cmdSet, sizeof(jbyte)));1202CHECK_ERROR(receiveBytes(connection, &packet->type.cmd.cmd, sizeof(jbyte)));1203}12041205CHECK_ERROR(receiveBytes(connection, &data_length, sizeof(jint)));12061207if (data_length < 0) {1208return SYS_ERR;1209} else if (data_length == 0) {1210packet->type.cmd.len = JDWP_HEADER_SIZE;1211packet->type.cmd.data = NULL;1212} else {1213packet->type.cmd.len = data_length + JDWP_HEADER_SIZE;1214packet->type.cmd.data = (*callback->alloc)(data_length);1215if (packet->type.cmd.data == NULL) {1216return SYS_ERR;1217}12181219error = receiveBytes(connection, packet->type.cmd.data, data_length);1220if (error != SYS_OK) {1221(*callback->free)(packet->type.cmd.data);1222return error;1223}1224}12251226return SYS_OK;1227}12281229jint1230shmemBase_receivePacket(SharedMemoryConnection *connection, jdwpPacket *packet)1231{1232ENTER_CONNECTION(connection);1233jint rc = shmemBase_receivePacket_internal(connection, packet);1234LEAVE_CONNECTION(connection);1235return rc;1236}12371238jint1239shmemBase_name(struct SharedMemoryTransport *transport, char **name)1240{1241*name = transport->name;1242return SYS_OK;1243}12441245jint1246shmemBase_getlasterror(char *msg, jint size) {1247char *errstr = (char *)sysTlsGet(tlsIndex);1248if (errstr != NULL) {1249strcpy(msg, errstr);1250return SYS_OK;1251} else {1252return SYS_ERR;1253}1254}125512561257void1258exitTransportWithError(char *message, char *fileName,1259char *date, int lineNumber)1260{1261JNIEnv *env;1262jint error;1263char buffer[500];12641265sprintf(buffer, "Shared Memory Transport \"%s\" (%s), line %d: %s\n",1266fileName, date, lineNumber, message);1267error = (*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2);1268if (error != JNI_OK) {1269/*1270* We're forced into a direct call to exit()1271*/1272fprintf(stderr, "%s", buffer);1273exit(-1);1274} else {1275(*env)->FatalError(env, buffer);1276}1277}127812791280