Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/transport/shmem/shmemBase.c
38813 views
/*1* Copyright (c) 1999, 2008, 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#define MIN(x,y) ((x)<(y)?(x):(y))3435/*36* This is the base shared memory transport implementation that is used37* by both front-end transports (through com.sun.tools.jdi) and38* back-end transports (through JDWP_OnLoad and the function tables39* it requires). It supports multiple connections for the benefit of the40* front-end client; the back end interface assumes only a single connection.41*/4243#define MAX_IPC_PREFIX 50 /* user-specified or generated name for */44/* shared memory seg and prefix for other IPC */45#define MAX_IPC_SUFFIX 25 /* suffix to shmem name for other IPC names */46#define MAX_IPC_NAME (MAX_IPC_PREFIX + MAX_IPC_SUFFIX)4748#define MAX_GENERATION_RETRIES 2049#define SHARED_BUFFER_SIZE 50005051#define CHECK_ERROR(expr) do { \52jint error = (expr); \53if (error != SYS_OK) { \54setLastError(error); \55return error; \56} \57} while (0)5859/*60* The following assertions should hold anytime the stream's mutex is not held61*/62#define STREAM_INVARIANT(stream) \63do { \64SHMEM_ASSERT((stream->shared->readOffset < SHARED_BUFFER_SIZE) \65&& (stream->shared->readOffset >= 0)); \66SHMEM_ASSERT((stream->shared->writeOffset < SHARED_BUFFER_SIZE) \67&& (stream->shared->writeOffset >= 0)); \68} while (0)6970/*71* Transports are duplex, so carve the shared memory into "streams",72* one used to send from client to server, the other vice versa.73*/74typedef struct SharedMemoryListener {75char mutexName[MAX_IPC_NAME];76char acceptEventName[MAX_IPC_NAME];77char attachEventName[MAX_IPC_NAME];78jboolean isListening;79jboolean isAccepted;80jlong acceptingPID;81jlong attachingPID;82} SharedListener;8384typedef struct SharedMemoryTransport {85char name[MAX_IPC_PREFIX];86sys_ipmutex_t mutex;87sys_event_t acceptEvent;88sys_event_t attachEvent;89sys_shmem_t sharedMemory;90SharedListener *shared;91} SharedMemoryTransport;9293/*94* Access must be syncronized. Holds one shared95* memory buffer and its state.96*/97typedef struct SharedStream {98char mutexName[MAX_IPC_NAME];99char hasDataEventName[MAX_IPC_NAME];100char hasSpaceEventName[MAX_IPC_NAME];101int readOffset;102int writeOffset;103jboolean isFull;104jbyte buffer[SHARED_BUFFER_SIZE];105} SharedStream;106107/*108* The two shared streams: client to server and109* server to client.110*/111typedef struct SharedMemory {112SharedStream toClient;113SharedStream toServer;114} SharedMemory;115116/*117* Local (to process) access to the shared memory118* stream. access to hasData and hasSpace synchronized119* by OS.120*/121typedef struct Stream {122sys_ipmutex_t mutex;123sys_event_t hasData;124sys_event_t hasSpace;125SharedStream *shared;126jint state;127} Stream;128129/*130* Values for Stream.state field above.131*/132#define STATE_CLOSED 0xDEAD133#define STATE_OPEN (STATE_CLOSED -1)134/*135* State checking macro. We compare against the STATE_OPEN value so136* that STATE_CLOSED and any other value will be considered closed.137* This catches a freed Stream as long as the memory page is still138* valid. If the memory page is gone, then there is little that we139* can do.140*/141#define IS_STATE_CLOSED(state) (state != STATE_OPEN)142143144typedef struct SharedMemoryConnection {145char name[MAX_IPC_NAME];146SharedMemory *shared;147sys_shmem_t sharedMemory;148Stream incoming;149Stream outgoing;150sys_process_t otherProcess;151sys_event_t shutdown; /* signalled to indicate shutdown */152} SharedMemoryConnection;153154static jdwpTransportCallback *callback;155static JavaVM *jvm;156static int tlsIndex;157158typedef jint (*CreateFunc)(char *name, void *arg);159160/*161* Set the per-thread error message (if not already set)162*/163static void164setLastErrorMsg(char *newmsg) {165char *msg;166167msg = (char *)sysTlsGet(tlsIndex);168if (msg == NULL) {169msg = (*callback->alloc)((int)strlen(newmsg)+1);170if (msg != NULL) {171strcpy(msg, newmsg);172}173sysTlsPut(tlsIndex, (void *)msg);174}175}176177/*178* Clear last per-thread error message179*/180static void181clearLastError() {182char* msg = (char *)sysTlsGet(tlsIndex);183if (msg != NULL) {184(*callback->free)(msg);185sysTlsPut(tlsIndex, NULL);186}187}188189/*190* Set the per-thread error message to the textual representation191* of the last system error (if not already set)192*/193static void194setLastError(jint error) {195char buf[128];196197switch (error) {198case SYS_OK : return; /* no-op */199case SYS_DIED : strcpy(buf, "Other process terminated"); break;200case SYS_TIMEOUT : strcpy(buf, "Timed out"); break;201default : sysGetLastError(buf, sizeof(buf));202}203setLastErrorMsg(buf);204}205206jint207shmemBase_initialize(JavaVM *vm, jdwpTransportCallback *cbPtr)208{209jvm = vm;210callback = cbPtr;211tlsIndex = sysTlsAlloc();212return SYS_OK;213}214215static jint216createWithGeneratedName(char *prefix, char *nameBuffer, CreateFunc func, void *arg)217{218jint error;219jint i = 0;220221do {222strcpy(nameBuffer, prefix);223if (i > 0) {224char buf[10];225sprintf(buf, ".%d", i+1);226strcat(nameBuffer, buf);227}228error = func(nameBuffer, arg);229i++;230} while ((error == SYS_INUSE) && (i < MAX_GENERATION_RETRIES));231232if (error != SYS_OK) {233setLastError(error);234}235236return error;237}238239typedef struct SharedMemoryArg {240jint size;241sys_shmem_t memory;242void *start;243} SharedMemoryArg;244245static jint246createSharedMem(char *name, void *ptr)247{248SharedMemoryArg *arg = ptr;249return sysSharedMemCreate(name, arg->size, &arg->memory, &arg->start);250}251252static jint253createMutex(char *name, void *arg)254{255sys_ipmutex_t *retArg = arg;256return sysIPMutexCreate(name, retArg);257}258259/*260* Creates named or unnamed event that is automatically reset261* (in other words, no need to reset event after it has signalled262* a thread).263*/264static jint265createEvent(char *name, void *arg)266{267sys_event_t *retArg = arg;268return sysEventCreate(name, retArg, JNI_FALSE);269}270271#define ADD_OFFSET(o1, o2) ((o1 + o2) % SHARED_BUFFER_SIZE)272#define FULL(stream) (stream->shared->isFull)273#define EMPTY(stream) ((stream->shared->writeOffset == stream->shared->readOffset) \274&& !stream->shared->isFull)275276static jint277leaveMutex(Stream *stream)278{279return sysIPMutexExit(stream->mutex);280}281282/* enter the stream's mutex and (optionally) check for a closed stream */283static jint284enterMutex(Stream *stream, sys_event_t event)285{286jint ret = sysIPMutexEnter(stream->mutex, event);287if (ret != SYS_OK) {288if (IS_STATE_CLOSED(stream->state)) {289setLastErrorMsg("stream closed");290}291return ret;292}293if (IS_STATE_CLOSED(stream->state)) {294setLastErrorMsg("stream closed");295(void)leaveMutex(stream);296return SYS_ERR;297}298return SYS_OK;299}300301/*302* Enter/exit with stream mutex held.303* On error, does not hold the stream mutex.304*/305static jint306waitForSpace(SharedMemoryConnection *connection, Stream *stream)307{308jint error = SYS_OK;309310/* Assumes mutex is held on call */311while ((error == SYS_OK) && FULL(stream)) {312CHECK_ERROR(leaveMutex(stream));313error = sysEventWait(connection->otherProcess, stream->hasSpace, 0);314if (error == SYS_OK) {315CHECK_ERROR(enterMutex(stream, connection->shutdown));316} else {317setLastError(error);318}319}320return error;321}322323static jint324signalSpace(Stream *stream)325{326return sysEventSignal(stream->hasSpace);327}328329/*330* Enter/exit with stream mutex held.331* On error, does not hold the stream mutex.332*/333static jint334waitForData(SharedMemoryConnection *connection, Stream *stream)335{336jint error = SYS_OK;337338/* Assumes mutex is held on call */339while ((error == SYS_OK) && EMPTY(stream)) {340CHECK_ERROR(leaveMutex(stream));341error = sysEventWait(connection->otherProcess, stream->hasData, 0);342if (error == SYS_OK) {343CHECK_ERROR(enterMutex(stream, connection->shutdown));344} else {345setLastError(error);346}347}348return error;349}350351static jint352signalData(Stream *stream)353{354return sysEventSignal(stream->hasData);355}356357358static jint359closeStream(Stream *stream, jboolean linger)360{361/*362* Lock stream during close - ignore shutdown event as we are363* closing down and shutdown should be signalled.364*/365CHECK_ERROR(enterMutex(stream, NULL));366367/* mark the stream as closed */368stream->state = STATE_CLOSED;369/* wake up waitForData() if it is in sysEventWait() */370sysEventSignal(stream->hasData);371sysEventClose(stream->hasData);372/* wake up waitForSpace() if it is in sysEventWait() */373sysEventSignal(stream->hasSpace);374sysEventClose(stream->hasSpace);375376/*377* If linger requested then give the stream a few seconds to378* drain before closing it.379*/380if (linger) {381int attempts = 10;382while (!EMPTY(stream) && attempts>0) {383CHECK_ERROR(leaveMutex(stream));384sysSleep(200);385CHECK_ERROR(enterMutex(stream, NULL));386attempts--;387}388}389390CHECK_ERROR(leaveMutex(stream));391sysIPMutexClose(stream->mutex);392return SYS_OK;393}394395/*396* Server creates stream.397*/398static int399createStream(char *name, Stream *stream)400{401jint error;402char prefix[MAX_IPC_PREFIX];403404sprintf(prefix, "%s.mutex", name);405error = createWithGeneratedName(prefix, stream->shared->mutexName,406createMutex, &stream->mutex);407if (error != SYS_OK) {408return error;409}410411sprintf(prefix, "%s.hasData", name);412error = createWithGeneratedName(prefix, stream->shared->hasDataEventName,413createEvent, &stream->hasData);414if (error != SYS_OK) {415(void)closeStream(stream, JNI_FALSE);416return error;417}418419sprintf(prefix, "%s.hasSpace", name);420error = createWithGeneratedName(prefix, stream->shared->hasSpaceEventName,421createEvent, &stream->hasSpace);422if (error != SYS_OK) {423(void)closeStream(stream, JNI_FALSE);424return error;425}426427stream->shared->readOffset = 0;428stream->shared->writeOffset = 0;429stream->shared->isFull = JNI_FALSE;430stream->state = STATE_OPEN;431return SYS_OK;432}433434435/*436* Initialization for the stream opened by the other process437*/438static int439openStream(Stream *stream)440{441jint error;442443CHECK_ERROR(sysIPMutexOpen(stream->shared->mutexName, &stream->mutex));444445error = sysEventOpen(stream->shared->hasDataEventName,446&stream->hasData);447if (error != SYS_OK) {448setLastError(error);449(void)closeStream(stream, JNI_FALSE);450return error;451}452453error = sysEventOpen(stream->shared->hasSpaceEventName,454&stream->hasSpace);455if (error != SYS_OK) {456setLastError(error);457(void)closeStream(stream, JNI_FALSE);458return error;459}460461stream->state = STATE_OPEN;462463return SYS_OK;464}465466/********************************************************************/467468static SharedMemoryConnection *469allocConnection(void)470{471/*472* TO DO: Track all allocated connections for clean shutdown?473*/474SharedMemoryConnection *conn = (*callback->alloc)(sizeof(SharedMemoryConnection));475if (conn != NULL) {476memset(conn, 0, sizeof(SharedMemoryConnection));477}478return conn;479}480481static void482freeConnection(SharedMemoryConnection *connection)483{484(*callback->free)(connection);485}486487static void488closeConnection(SharedMemoryConnection *connection)489{490/*491* Signal all threads accessing this connection that we are492* shutting down.493*/494if (connection->shutdown) {495sysEventSignal(connection->shutdown);496}497498499(void)closeStream(&connection->outgoing, JNI_TRUE);500(void)closeStream(&connection->incoming, JNI_FALSE);501502if (connection->sharedMemory) {503sysSharedMemClose(connection->sharedMemory, connection->shared);504}505if (connection->otherProcess) {506sysProcessClose(connection->otherProcess);507}508509/*510* Ideally we should close the connection->shutdown event and511* free the connection structure. However as closing the512* connection is asynchronous it means that other threads may513* still be accessing the connection structure. On Win32 this514* means we leak 132 bytes and one event per connection. This515* memory will be reclaim at process exit.516*517* if (connection->shutdown)518* sysEventClose(connection->shutdown);519* freeConnection(connection);520*/521}522523524/*525* For client: connect to the shared memory. Open incoming and526* outgoing streams.527*/528static jint529openConnection(SharedMemoryTransport *transport, jlong otherPID,530SharedMemoryConnection **connectionPtr)531{532jint error;533534SharedMemoryConnection *connection = allocConnection();535if (connection == NULL) {536return SYS_NOMEM;537}538539sprintf(connection->name, "%s.%ld", transport->name, sysProcessGetID());540error = sysSharedMemOpen(connection->name, &connection->sharedMemory,541&connection->shared);542if (error != SYS_OK) {543closeConnection(connection);544return error;545}546547/* This process is the client */548connection->incoming.shared = &connection->shared->toClient;549connection->outgoing.shared = &connection->shared->toServer;550551error = openStream(&connection->incoming);552if (error != SYS_OK) {553closeConnection(connection);554return error;555}556557error = openStream(&connection->outgoing);558if (error != SYS_OK) {559closeConnection(connection);560return error;561}562563error = sysProcessOpen(otherPID, &connection->otherProcess);564if (error != SYS_OK) {565setLastError(error);566closeConnection(connection);567return error;568}569570/*571* Create an event that signals that the connection is shutting572* down. The event is unnamed as it's process local, and is573* manually reset (so that signalling the event will signal574* all threads waiting on it).575*/576error = sysEventCreate(NULL, &connection->shutdown, JNI_TRUE);577if (error != SYS_OK) {578setLastError(error);579closeConnection(connection);580return error;581}582583*connectionPtr = connection;584return SYS_OK;585}586587/*588* For server: create the shared memory. Create incoming and589* outgoing streams.590*/591static jint592createConnection(SharedMemoryTransport *transport, jlong otherPID,593SharedMemoryConnection **connectionPtr)594{595jint error;596char streamPrefix[MAX_IPC_NAME];597598SharedMemoryConnection *connection = allocConnection();599if (connection == NULL) {600return SYS_NOMEM;601}602603sprintf(connection->name, "%s.%ld", transport->name, otherPID);604error = sysSharedMemCreate(connection->name, sizeof(SharedMemory),605&connection->sharedMemory, &connection->shared);606if (error != SYS_OK) {607closeConnection(connection);608return error;609}610611memset(connection->shared, 0, sizeof(SharedMemory));612613/* This process is the server */614connection->incoming.shared = &connection->shared->toServer;615connection->outgoing.shared = &connection->shared->toClient;616617strcpy(streamPrefix, connection->name);618strcat(streamPrefix, ".ctos");619error = createStream(streamPrefix, &connection->incoming);620if (error != SYS_OK) {621closeConnection(connection);622return error;623}624625strcpy(streamPrefix, connection->name);626strcat(streamPrefix, ".stoc");627error = createStream(streamPrefix, &connection->outgoing);628if (error != SYS_OK) {629closeConnection(connection);630return error;631}632633error = sysProcessOpen(otherPID, &connection->otherProcess);634if (error != SYS_OK) {635setLastError(error);636closeConnection(connection);637return error;638}639640/*641* Create an event that signals that the connection is shutting642* down. The event is unnamed as it's process local, and is643* manually reset (so that a signalling the event will signal644* all threads waiting on it).645*/646error = sysEventCreate(NULL, &connection->shutdown, JNI_TRUE);647if (error != SYS_OK) {648setLastError(error);649closeConnection(connection);650return error;651}652653*connectionPtr = connection;654return SYS_OK;655}656657/********************************************************************/658659static SharedMemoryTransport *660allocTransport(void)661{662/*663* TO DO: Track all allocated transports for clean shutdown?664*/665return (*callback->alloc)(sizeof(SharedMemoryTransport));666}667668static void669freeTransport(SharedMemoryTransport *transport)670{671(*callback->free)(transport);672}673674static void675closeTransport(SharedMemoryTransport *transport)676{677sysIPMutexClose(transport->mutex);678sysEventClose(transport->acceptEvent);679sysEventClose(transport->attachEvent);680sysSharedMemClose(transport->sharedMemory, transport->shared);681freeTransport(transport);682}683684static int685openTransport(const char *address, SharedMemoryTransport **transportPtr)686{687jint error;688SharedMemoryTransport *transport;689690transport = allocTransport();691if (transport == NULL) {692return SYS_NOMEM;693}694memset(transport, 0, sizeof(*transport));695696if (strlen(address) >= MAX_IPC_PREFIX) {697char buf[128];698sprintf(buf, "Error: address strings longer than %d characters are invalid\n", MAX_IPC_PREFIX);699setLastErrorMsg(buf);700closeTransport(transport);701return SYS_ERR;702}703704error = sysSharedMemOpen(address, &transport->sharedMemory, &transport->shared);705if (error != SYS_OK) {706setLastError(error);707closeTransport(transport);708return error;709}710strcpy(transport->name, address);711712error = sysIPMutexOpen(transport->shared->mutexName, &transport->mutex);713if (error != SYS_OK) {714setLastError(error);715closeTransport(transport);716return error;717}718719error = sysEventOpen(transport->shared->acceptEventName,720&transport->acceptEvent);721if (error != SYS_OK) {722setLastError(error);723closeTransport(transport);724return error;725}726727error = sysEventOpen(transport->shared->attachEventName,728&transport->attachEvent);729if (error != SYS_OK) {730setLastError(error);731closeTransport(transport);732return error;733}734735*transportPtr = transport;736return SYS_OK;737}738739static jint740createTransport(const char *address, SharedMemoryTransport **transportPtr)741{742SharedMemoryTransport *transport;743jint error;744char prefix[MAX_IPC_PREFIX];745746747748transport = allocTransport();749if (transport == NULL) {750return SYS_NOMEM;751}752memset(transport, 0, sizeof(*transport));753754if ((address == NULL) || (address[0] == '\0')) {755SharedMemoryArg arg;756arg.size = sizeof(SharedListener);757error = createWithGeneratedName("javadebug", transport->name,758createSharedMem, &arg);759transport->shared = arg.start;760transport->sharedMemory = arg.memory;761} else {762if (strlen(address) >= MAX_IPC_PREFIX) {763char buf[128];764sprintf(buf, "Error: address strings longer than %d characters are invalid\n", MAX_IPC_PREFIX);765setLastErrorMsg(buf);766closeTransport(transport);767return SYS_ERR;768}769strcpy(transport->name, address);770error = sysSharedMemCreate(address, sizeof(SharedListener),771&transport->sharedMemory, &transport->shared);772}773if (error != SYS_OK) {774setLastError(error);775closeTransport(transport);776return error;777}778779memset(transport->shared, 0, sizeof(SharedListener));780transport->shared->acceptingPID = sysProcessGetID();781782sprintf(prefix, "%s.mutex", transport->name);783error = createWithGeneratedName(prefix, transport->shared->mutexName,784createMutex, &transport->mutex);785if (error != SYS_OK) {786closeTransport(transport);787return error;788}789790sprintf(prefix, "%s.accept", transport->name);791error = createWithGeneratedName(prefix, transport->shared->acceptEventName,792createEvent, &transport->acceptEvent);793if (error != SYS_OK) {794closeTransport(transport);795return error;796}797798sprintf(prefix, "%s.attach", transport->name);799error = createWithGeneratedName(prefix, transport->shared->attachEventName,800createEvent, &transport->attachEvent);801if (error != SYS_OK) {802closeTransport(transport);803return error;804}805806*transportPtr = transport;807return SYS_OK;808}809810811jint812shmemBase_listen(const char *address, SharedMemoryTransport **transportPtr)813{814int error;815816clearLastError();817818error = createTransport(address, transportPtr);819if (error == SYS_OK) {820(*transportPtr)->shared->isListening = JNI_TRUE;821}822return error;823}824825826jint827shmemBase_accept(SharedMemoryTransport *transport,828long timeout,829SharedMemoryConnection **connectionPtr)830{831jint error;832SharedMemoryConnection *connection;833834clearLastError();835836CHECK_ERROR(sysEventWait(NULL, transport->attachEvent, timeout));837838error = createConnection(transport, transport->shared->attachingPID,839&connection);840if (error != SYS_OK) {841/*842* Reject the attacher843*/844transport->shared->isAccepted = JNI_FALSE;845sysEventSignal(transport->acceptEvent);846847freeConnection(connection);848return error;849}850851transport->shared->isAccepted = JNI_TRUE;852error = sysEventSignal(transport->acceptEvent);853if (error != SYS_OK) {854/*855* No real point trying to reject it.856*/857closeConnection(connection);858return error;859}860861*connectionPtr = connection;862return SYS_OK;863}864865static jint866doAttach(SharedMemoryTransport *transport, long timeout)867{868transport->shared->attachingPID = sysProcessGetID();869CHECK_ERROR(sysEventSignal(transport->attachEvent));870CHECK_ERROR(sysEventWait(NULL, transport->acceptEvent, timeout));871return SYS_OK;872}873874jint875shmemBase_attach(const char *addressString, long timeout, SharedMemoryConnection **connectionPtr)876{877int error;878SharedMemoryTransport *transport;879jlong acceptingPID;880881clearLastError();882883error = openTransport(addressString, &transport);884if (error != SYS_OK) {885return error;886}887888/* lock transport - no additional event to wait on as no connection yet */889error = sysIPMutexEnter(transport->mutex, NULL);890if (error != SYS_OK) {891setLastError(error);892closeTransport(transport);893return error;894}895896if (transport->shared->isListening) {897error = doAttach(transport, timeout);898if (error == SYS_OK) {899acceptingPID = transport->shared->acceptingPID;900}901} else {902/* Not listening: error */903error = SYS_ERR;904}905906sysIPMutexExit(transport->mutex);907if (error != SYS_OK) {908closeTransport(transport);909return error;910}911912error = openConnection(transport, acceptingPID, connectionPtr);913914closeTransport(transport);915916return error;917}918919920921922void923shmemBase_closeConnection(SharedMemoryConnection *connection)924{925clearLastError();926closeConnection(connection);927}928929void930shmemBase_closeTransport(SharedMemoryTransport *transport)931{932clearLastError();933closeTransport(transport);934}935936jint937shmemBase_sendByte(SharedMemoryConnection *connection, jbyte data)938{939Stream *stream = &connection->outgoing;940SharedStream *shared = stream->shared;941int offset;942943clearLastError();944945CHECK_ERROR(enterMutex(stream, connection->shutdown));946CHECK_ERROR(waitForSpace(connection, stream));947SHMEM_ASSERT(!FULL(stream));948offset = shared->writeOffset;949shared->buffer[offset] = data;950shared->writeOffset = ADD_OFFSET(offset, 1);951shared->isFull = (shared->readOffset == shared->writeOffset);952953STREAM_INVARIANT(stream);954CHECK_ERROR(leaveMutex(stream));955956CHECK_ERROR(signalData(stream));957958return SYS_OK;959}960961jint962shmemBase_receiveByte(SharedMemoryConnection *connection, jbyte *data)963{964Stream *stream = &connection->incoming;965SharedStream *shared = stream->shared;966int offset;967968clearLastError();969970CHECK_ERROR(enterMutex(stream, connection->shutdown));971CHECK_ERROR(waitForData(connection, stream));972SHMEM_ASSERT(!EMPTY(stream));973offset = shared->readOffset;974*data = shared->buffer[offset];975shared->readOffset = ADD_OFFSET(offset, 1);976shared->isFull = JNI_FALSE;977978STREAM_INVARIANT(stream);979CHECK_ERROR(leaveMutex(stream));980981CHECK_ERROR(signalSpace(stream));982983return SYS_OK;984}985986static jint987sendBytes(SharedMemoryConnection *connection, const void *bytes, jint length)988{989Stream *stream = &connection->outgoing;990SharedStream *shared = stream->shared;991jint fragmentStart;992jint fragmentLength;993jint index = 0;994jint maxLength;995996clearLastError();997998CHECK_ERROR(enterMutex(stream, connection->shutdown));999while (index < length) {1000CHECK_ERROR(waitForSpace(connection, stream));1001SHMEM_ASSERT(!FULL(stream));10021003fragmentStart = shared->writeOffset;10041005if (fragmentStart < shared->readOffset) {1006maxLength = shared->readOffset - fragmentStart;1007} else {1008maxLength = SHARED_BUFFER_SIZE - fragmentStart;1009}1010fragmentLength = MIN(maxLength, length - index);1011memcpy(shared->buffer + fragmentStart, (jbyte *)bytes + index, fragmentLength);1012shared->writeOffset = ADD_OFFSET(fragmentStart, fragmentLength);1013index += fragmentLength;10141015shared->isFull = (shared->readOffset == shared->writeOffset);10161017STREAM_INVARIANT(stream);1018CHECK_ERROR(signalData(stream));10191020}1021CHECK_ERROR(leaveMutex(stream));10221023return SYS_OK;1024}102510261027/*1028* Send packet header followed by data.1029*/1030jint1031shmemBase_sendPacket(SharedMemoryConnection *connection, const jdwpPacket *packet)1032{1033jint data_length;10341035clearLastError();10361037CHECK_ERROR(sendBytes(connection, &packet->type.cmd.id, sizeof(jint)));1038CHECK_ERROR(sendBytes(connection, &packet->type.cmd.flags, sizeof(jbyte)));10391040if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {1041CHECK_ERROR(sendBytes(connection, &packet->type.reply.errorCode, sizeof(jshort)));1042} else {1043CHECK_ERROR(sendBytes(connection, &packet->type.cmd.cmdSet, sizeof(jbyte)));1044CHECK_ERROR(sendBytes(connection, &packet->type.cmd.cmd, sizeof(jbyte)));1045}10461047data_length = packet->type.cmd.len - 11;1048SHMEM_GUARANTEE(data_length >= 0);1049CHECK_ERROR(sendBytes(connection, &data_length, sizeof(jint)));10501051if (data_length > 0) {1052CHECK_ERROR(sendBytes(connection, packet->type.cmd.data, data_length));1053}10541055return SYS_OK;1056}10571058static jint1059receiveBytes(SharedMemoryConnection *connection, void *bytes, jint length)1060{1061Stream *stream = &connection->incoming;1062SharedStream *shared = stream->shared;1063jint fragmentStart;1064jint fragmentLength;1065jint index = 0;1066jint maxLength;10671068clearLastError();10691070CHECK_ERROR(enterMutex(stream, connection->shutdown));1071while (index < length) {1072CHECK_ERROR(waitForData(connection, stream));1073SHMEM_ASSERT(!EMPTY(stream));10741075fragmentStart = shared->readOffset;1076if (fragmentStart < shared->writeOffset) {1077maxLength = shared->writeOffset - fragmentStart;1078} else {1079maxLength = SHARED_BUFFER_SIZE - fragmentStart;1080}1081fragmentLength = MIN(maxLength, length - index);1082memcpy((jbyte *)bytes + index, shared->buffer + fragmentStart, fragmentLength);1083shared->readOffset = ADD_OFFSET(fragmentStart, fragmentLength);1084index += fragmentLength;10851086shared->isFull = JNI_FALSE;10871088STREAM_INVARIANT(stream);1089CHECK_ERROR(signalSpace(stream));1090}1091CHECK_ERROR(leaveMutex(stream));10921093return SYS_OK;1094}10951096/*1097* Read packet header and insert into packet structure.1098* Allocate space for the data and fill it in.1099*/1100jint1101shmemBase_receivePacket(SharedMemoryConnection *connection, jdwpPacket *packet)1102{1103jint data_length;1104jint error;11051106clearLastError();11071108CHECK_ERROR(receiveBytes(connection, &packet->type.cmd.id, sizeof(jint)));1109CHECK_ERROR(receiveBytes(connection, &packet->type.cmd.flags, sizeof(jbyte)));11101111if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {1112CHECK_ERROR(receiveBytes(connection, &packet->type.reply.errorCode, sizeof(jshort)));1113} else {1114CHECK_ERROR(receiveBytes(connection, &packet->type.cmd.cmdSet, sizeof(jbyte)));1115CHECK_ERROR(receiveBytes(connection, &packet->type.cmd.cmd, sizeof(jbyte)));1116}11171118CHECK_ERROR(receiveBytes(connection, &data_length, sizeof(jint)));11191120if (data_length < 0) {1121return SYS_ERR;1122} else if (data_length == 0) {1123packet->type.cmd.len = 11;1124packet->type.cmd.data = NULL;1125} else {1126packet->type.cmd.len = data_length + 11;1127packet->type.cmd.data = (*callback->alloc)(data_length);1128if (packet->type.cmd.data == NULL) {1129return SYS_ERR;1130}11311132error = receiveBytes(connection, packet->type.cmd.data, data_length);1133if (error != SYS_OK) {1134(*callback->free)(packet->type.cmd.data);1135return error;1136}1137}11381139return SYS_OK;1140}11411142jint1143shmemBase_name(struct SharedMemoryTransport *transport, char **name)1144{1145*name = transport->name;1146return SYS_OK;1147}11481149jint1150shmemBase_getlasterror(char *msg, jint size) {1151char *errstr = (char *)sysTlsGet(tlsIndex);1152if (errstr != NULL) {1153strcpy(msg, errstr);1154return SYS_OK;1155} else {1156return SYS_ERR;1157}1158}115911601161void1162exitTransportWithError(char *message, char *fileName,1163char *date, int lineNumber)1164{1165JNIEnv *env;1166jint error;1167char buffer[500];11681169sprintf(buffer, "Shared Memory Transport \"%s\" (%s), line %d: %s\n",1170fileName, date, lineNumber, message);1171error = (*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2);1172if (error != JNI_OK) {1173/*1174* We're forced into a direct call to exit()1175*/1176fprintf(stderr, "%s", buffer);1177exit(-1);1178} else {1179(*env)->FatalError(env, buffer);1180}1181}118211831184