Commit c740918b authored by Vít Kabele's avatar Vít Kabele

Merge branch 'fasttag' into shvm-flat

* fasttag: (64 commits)
  Include event number in JVMTI error check.
  Cosmetic changes
  Tweak byte buffer interface and update dependent files
  Cleanup and update to use the new buffer and buffer packing ops
  Update Makefile to compile bytebuffer
  Update byte buffer implementation
  Start compiling bufferbase.c and bufferpack.c
  Data packing operations for the simple byte buffer
  Simple implementation of expandable byte buffer
  Clean up and explain glbuffer_commit()
  Reuse __enqueue_and_invalidate_payload() in glbuffer_commit()
  Rename correct_cmd_buff_pos() to __shift_tag_positions
  Rename glbuffer_new() to __to_buff_alloc_buffers()
  Cleanup loops of over array of total-order buffer structures
  Cosmetic changes
  Pass JVMTI reference into globalbuffer methods.
  Rename local jvmti_env to local_jvmti
  Cosmetic changes
  Use "jni" instead of "jni_env" for conciseness
  Cleanup pack_object()
  ...

# Conflicts:
#	src-shvm-agent/buffer.h
#	src-shvm-agent/dislreagent.c
#	src-shvm-agent/netref.h
parents f02dafc0 438b5748
Pipeline #4521 passed with stages
in 3 minutes and 44 seconds
# Backup files
*~
# Generated dependency files
src-disl-agent/*.d
src-disl-agent/linux-*
src-disl-agent/windows-*
*.d
# Compiled shared libraries
*.so
......@@ -17,12 +18,15 @@ examples/**/*.jar
# Logs
*.log
# Output directories
src-disl-agent/linux-*
src-disl-agent/windows-*
# Anything in the output
output/*
# Libraries
# Runtime libraries
lib/*/*.jar
# Fallout from method uid generator
methodid.txt
......@@ -58,7 +58,12 @@ endif
# Source and object files needed to create the library
SOURCES = dislreagent.c
SOURCES = common.c jvmtiutil.c config.c \
shared/bytebuffer.c shared/bufferpack.c \
shared/blockingqueue.c \
shared/threadlocal.c shared/messagetype.c \
tagger.c sender.c dislreagent.c pbmanager.c redispatcher.c netref.c \
globalbuffer.c tlocalbuffer.c freehandler.c
HEADERS = $(wildcard *.h)
GENSRCS =
......@@ -92,8 +97,8 @@ endif
CFLAGS += -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/$(JDK_TARGET)
# Source code options
CFLAGS += -W -Wall -Wextra -Wno-unused-parameter
#CFLAGS += -std=gnu99 -W -Wall -Wextra -Wno-unused-parameter
#CFLAGS += -W -Wall -Wextra -Wno-unused-parameter
CFLAGS += -std=gnu99 -W -Wall -Wextra -Wno-unused-parameter
# Fix-up quirks before first target
-include Makefile.quirks
......
#ifndef _BLOCKINGQUEUE_H
#define _BLOCKINGQUEUE_H
#include <string.h>
#include <pthread.h>
#include <jvmti.h>
#include <jni.h>
#include "jvmtihelper.h"
typedef struct {
// array of elements
char * qarray;
size_t qa_size;
size_t qa_element_size;
size_t first;
size_t occupied;
pthread_mutex_t mutex;
pthread_cond_t cond;
jvmtiEnv * jvmti;
} blocking_queue;
// ** Monitor helper functions **
static void _bq_monitor_enter(blocking_queue * bq) {
pthread_mutex_lock(&(bq->mutex));
}
static void _bq_monitor_exit(blocking_queue * bq) {
pthread_mutex_unlock(&(bq->mutex));
}
static void _bq_monitor_wait(blocking_queue * bq) {
pthread_cond_wait(&(bq->cond), &(bq->mutex));
}
static void _bq_monitor_notify_all(blocking_queue * bq) {
pthread_cond_broadcast(&(bq->cond));
}
// ** Blocking queue functions **
void bq_create(jvmtiEnv *jvmti, blocking_queue * bq, size_t queue_capacity,
size_t queue_element_size) {
check_std_error((bq == NULL), TRUE, "Invalid blocking queue structure");
bq->qarray = malloc(queue_capacity * queue_element_size);
bq->qa_size = queue_capacity;
bq->qa_element_size = queue_element_size;
bq->first = 0;
bq->occupied = 0;
// create lock and cond
int pci = pthread_cond_init(&(bq->cond), NULL);
check_std_error((pci != 0), TRUE, "Cannot create pthread condition");
int pmi = pthread_mutex_init(&(bq->mutex), NULL);
check_std_error((pmi != 0), TRUE, "Cannot create pthread mutex");
bq->jvmti = jvmti;
}
void bq_term (blocking_queue * bq) {
_bq_monitor_enter(bq); {
// delete array
free(bq->qarray);
bq->qarray = NULL;
}
_bq_monitor_exit(bq);
// destroy lock and cond
pthread_mutex_destroy(&(bq->mutex));
pthread_cond_destroy(&(bq->cond));
}
void bq_push(blocking_queue * bq, void * data) {
_bq_monitor_enter(bq); {
// wait for some empty space
while(bq->occupied == bq->qa_size) {
_bq_monitor_wait(bq);
}
// add data
size_t last = (bq->first + bq->occupied) % bq->qa_size;
size_t last_pos = last * bq->qa_element_size;
memcpy(&((bq->qarray)[last_pos]), data, bq->qa_element_size);
++(bq->occupied);
// notify
_bq_monitor_notify_all(bq);
}
_bq_monitor_exit(bq);
}
void bq_pop(blocking_queue * bq, void * empty) {
_bq_monitor_enter(bq); {
// wait for some item
while(bq->occupied == 0) {
_bq_monitor_wait(bq);
}
// get the data
size_t first_pos = bq->first * bq->qa_element_size;
memcpy(empty, &((bq->qarray)[first_pos]), bq->qa_element_size);
// insert 0 - better problem detection
memset(&((bq->qarray)[first_pos]), 0, bq->qa_element_size);
bq->first = (bq->first + 1) % bq->qa_size;
--(bq->occupied);
// notify
_bq_monitor_notify_all(bq);
}
_bq_monitor_exit(bq);
}
size_t bq_length(blocking_queue * bq) {
size_t length = 0;
_bq_monitor_enter(bq); {
length = bq->occupied;
}
_bq_monitor_exit(bq);
return length;
}
#endif /* _BLOCKINGQUEUE_H */
#ifndef _BUFFER_H
#define _BUFFER_H
#include <stdlib.h>
#include <string.h>
#include "jvmtihelper.h"
// initial buffer size
static const size_t INIT_BUFF_SIZE = 512;
typedef struct {
unsigned char * buff;
size_t occupied;
size_t capacity;
} buffer;
// ******************* Buffer routines *******************
/*
* buffer_alloc()
*
* Allocate the space for buffer. To free the space see buffer_free()
*/
void
buffer_alloc(buffer * b)
{
b->buff = (unsigned char *) malloc(INIT_BUFF_SIZE);
b->capacity = INIT_BUFF_SIZE;
b->occupied = 0;
}
/*
* buffer_free()
*
* Free the allocated space for the buffer
*/
void
buffer_free(buffer * b)
{
free(b->buff);
b->buff = NULL;
b->capacity = 0;
b->occupied = 0;
}
void buffer_fill(buffer * b, const void * data, size_t data_length) {
// not enough free space - extend buffer
if(b->capacity - b->occupied < data_length) {
unsigned char * old_buff = b->buff;
// alloc as much as needed to be able to insert data
size_t new_capacity = 2 * b->capacity;
while(new_capacity - b->occupied < data_length) {
new_capacity *= 2;
}
b->buff = (unsigned char *) malloc(new_capacity);
b->capacity = new_capacity;
memcpy(b->buff, old_buff, b->occupied);
free(old_buff);
}
memcpy(b->buff + b->occupied, data, data_length);
b->occupied += data_length;
}
// the space has to be already filled with data - no extensions
void buffer_fill_at_pos(buffer * b, size_t pos, const void * data,
size_t data_length) {
// space is not filled already - error
if(b->occupied < pos + data_length) {
check_error(TRUE, "Filling buffer at non-occupied position.");
}
memcpy(b->buff + pos, data, data_length);
}
/*
* buffer_read()
*
* Copy the amount of data specified in data_length from buffer specified by
* b, starting at position pos (number of bytes from the start of the buffer)
* to place specified by parameter data.
*/
void
buffer_read(buffer * b, size_t pos, void * data, size_t data_length)
{
memcpy(data, b->buff + pos, data_length);
}
/*
* buffer_filled(buffer * b)
*
* Returns the number of occupied bytes in given buffer
*/
size_t
buffer_filled(buffer * b)
{
return b->occupied;
}
/*
* buffer_clean(buffer * b)
*
* Clean the buffer by setting the number of occupied bytes to zero. This will
* not affect the data stored.
*/
void
buffer_clean(buffer * b)
{
b->occupied = 0;
}
#endif /* _BUFFER_H */
#ifndef _BUFFPACK_H
#define _BUFFPACK_H
#if defined (__APPLE__) && defined (__MACH__)
#include <machine/endian.h>
#if BYTE_ORDER == BIG_ENDIAN
#define htobe64(x) (x)
#else // BYTE_ORDER != BIG_ENDIAN
#define htobe64(x) __DARWIN_OSSwapInt64((x))
#endif
#else // !(__APPLE__ && __MACH__)
#include <endian.h>
#endif
// Disabled check to make it compile under OS X with clang/LLVM.
//#ifndef __STDC_IEC_559__
//#error "Requires IEEE 754 floating point!"
//#endif
#include "jvmtihelper.h"
#include "buffer.h"
// interpret bytes differently
union float_jint {
float f;
jint i;
};
// interpret bytes differently
union double_jlong {
double d;
jlong l;
};
void pack_boolean(buffer * buff, jboolean to_send) {
buffer_fill(buff, &to_send, sizeof(jboolean));
}
void pack_byte(buffer * buff, jbyte to_send) {
buffer_fill(buff, &to_send, sizeof(jbyte));
}
void pack_char(buffer * buff, jchar to_send) {
jchar nts = htons(to_send);
buffer_fill(buff, &nts, sizeof(jchar));
}
void pack_short(buffer * buff, jshort to_send) {
jshort nts = htons(to_send);
buffer_fill(buff, &nts, sizeof(jshort));
}
void pack_int(buffer * buff, jint to_send) {
jint nts = htonl(to_send);
buffer_fill(buff, &nts, sizeof(jint));
}
void pack_long(buffer * buff, jlong to_send) {
jlong nts = htobe64(to_send);
buffer_fill(buff, &nts, sizeof(jlong));
}
void pack_float(buffer * buff, jfloat to_send) {
// macro ensures that the formating of the float is correct
// so make "int" from it and send it
union float_jint convert;
convert.f = to_send;
pack_int(buff, convert.i);
}
void pack_double(buffer * buff, jdouble to_send) {
// macro ensures that the formating of the double is correct
// so make "long" from it and send it
union double_jlong convert;
convert.d = to_send;
pack_long(buff, convert.l);
}
void pack_string_utf8(buffer * buff, const void * string_utf8,
uint16_t size_in_bytes) {
// send length first
uint16_t nsize = htons(size_in_bytes);
buffer_fill(buff, &nsize, sizeof(uint16_t));
buffer_fill(buff, string_utf8, size_in_bytes);
}
void pack_bytes(buffer * buff, const void * data, jint size) {
buffer_fill(buff, data, size);
}
#endif /* _BUFFPACK_H */
#ifndef _COMM_H
#define _COMM_H
#include <sys/types.h>
#include <sys/socket.h>
#include "jvmtihelper.h"
// sends data over network
void send_data(int sockfd, const void * data, int data_len) {
int sent = 0;
while (sent != data_len) {
int res = send(sockfd, ((unsigned char *)data) + sent,
(data_len - sent), 0);
check_std_error(res, -1, "Error while sending data to server");
sent += res;
}
}
// receives data from network
void rcv_data(int sockfd, void * data, int data_len) {
int received = 0;
while (received != data_len) {
int res = recv(sockfd, ((unsigned char *)data) + received,
(data_len - received), 0);
check_std_error(res, -1, "Error while receiving data from server");
received += res;
}
}
#endif /* _COMM_H */
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <strings.h>
//
/**
* Returns the index of the given value in the given array of values.
* Returns -1 if the value could not be found among the allowed values.
*/
int
find_value_index (
const char * restrict strval, const char * restrict values [], int nvals
) {
for (int i = 0; i < nvals; i++) {
if (strcasecmp (values [i], strval) == 0) {
return i;
}
}
return -1;
}
//
/**
* Reports an error and terminates the program. This function implements the
* slow path of check_error(). It prints the given error message and exits with
* an error code indicating a generic error.
*/
void
die_with_error (const char * restrict format, va_list args) {
fprintf (stderr, AGENT_NAME ": error: ");
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
exit (ERROR_GENERIC);
}
/**
* Reports a standard library error and terminates the program. This function
* implements the slow path of check_std_error(). It prints the given error
* message along with the error message provided by the standard library and
* exits with an error code indicating failure in standard library call.
*/
void
die_with_std_error (int errnum, const char * restrict format, va_list args) {
char * cause = strerror (errnum);
fprintf (stderr, AGENT_NAME ": std-error: %s\n", cause);
fprintf (stderr, AGENT_NAME ": ");
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
exit (ERROR_STD);
}
#ifdef MINGW
/**
* Obtains an error message for the given error code.
* Allocates a new string that has to be released by the caller.
*/
static char *
__get_error_message (const DWORD msg_id) {
LPVOID msg_buffer = NULL;
size_t size = FormatMessageA (
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, msg_id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &msg_buffer, 0, NULL
);
if (size != 0 && msg_buffer != NULL) {
char * message = strdup (msg_buffer);
LocalFree (msg_buffer);
return message;
} else {
static const char * msg_format = "unknown error (%d)";
size_t msg_length = strlen (msg_format) + ((sizeof(DWORD) * 8) / 3) + 1;
char * message = (char *) malloc (msg_length);
if (message != NULL) {
snprintf (message, msg_length, msg_format, msg_id);
}
return message;
}
}
/**
* Reports a windows error and terminates the program. This function
* implements the slow path of check_win_error(). It prints the given error
* message along with the error message provided by windows and
* exits with an error code indicating failure in standard library call.
*/
void
die_with_win_error (DWORD errnum, const char * restrict format, va_list args) {
const char * restrict cause = __get_error_message (errnum);
fprintf (stderr, AGENT_NAME ": std-error: %s\n", cause);
if (cause != NULL) {
free (cause);
}
fprintf (stderr, AGENT_NAME ": ");
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
exit (ERROR_STD);
}
#endif /* MINGW */
#ifndef _COMMON_H_
#define _COMMON_H_
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include <errno.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#ifdef MINGW
#include <winsock2.h>
#include <windows.h>
#endif
/**
* Compiler attributes.
*/
#define PACKED __attribute__ ((__packed__))
#if defined(WHOLE) && __has_attribute(externally_visible)
#define VISIBLE __attribute__ ((externally_visible))
#else
#define VISIBLE
#endif
/**
* Returns the size of an array in array elements.
*/
#define sizeof_array(array) \
(sizeof (array) / sizeof ((array) [0]))
/**
* Returns the size of a structure member.
*/
#define sizeof_member(type, member) \
(sizeof (((type *) 0)->member))
/**
* Prints a debug message to stdout, unless NDEBUG is defined.
*
* @format format string for printf
* @args arguments associated with the format string
*
*/
#ifdef NDEBUG
# define debug(args...) do {} while (0)
#else
# define debug(args...) fprintf (stdout, args); fflush (stdout)
#endif
#define ldebug(args...) { \
debug ("%s:%d: ", __FUNCTION__, __LINE__); \
debug (args); \
}
//
#define warn(args...) { \
fprintf (stderr, AGENT_NAME ": warning: "); \
fprintf (stderr, args); \
}
//
int find_value_index (
const char * restrict strval, const char * restrict values [], int nvals
);
//
#define ERROR_GENERIC 10000
#define ERROR_SERVER 10003
#define ERROR_STD 10002
#define ERROR_JVMTI 10003
#define AGENT_NAME "svm-agent"
//
void die_with_error (const char * format, va_list args);
void die_with_std_error (int errnum, const char * format, va_list args);
/**
* Reports a general error and terminates the program if the provided
* error condition is true.
*/
static inline void
check_error (bool error, const char * format, ...) {
if (error) {
va_list args;
va_start (args, format);
die_with_error (format, args);
va_end (args);
}
}
/**
* Reports a standard library error and terminates the program if the provided
* error condition is true.
*/
static inline void
check_std_error (bool error, const char * format, ...) {
if (error) {
va_list args;
va_start (args, format);
die_with_std_error (errno, format, args);
va_end (args);
}
}
//
#ifdef MINGW
void die_with_win_error (DWORD errnum, const char * message, va_list args);
/**
* Reports a windows error and terminates the program if the provided
* error condition is true.
*/
static inline void
check_win_error (bool error, const char * format, ...) {
if (error) {
va_list args;
va_start (args, format);
die_with_win_error (GetLastError (), format, args);
va_end (args);
}
}
#endif /* MINGW */
#endif /* _COMMON_H_ */
#include "config.h"