From 32ba8efc6862ce7b9da7f5e59ab00d07c28e1401 Mon Sep 17 00:00:00 2001
From: Anders Blomdell <anders.blomdell@control.lth.se>
Date: Wed, 5 Jun 2013 16:43:30 +0200
Subject: [PATCH] First stab at removing the O(n) signature search from
 labcomm.

---
 examples/simple/compile.sh                   | 18 ++---
 lib/c/Makefile                               |  5 +-
 lib/c/labcomm.c                              | 70 ++++----------------
 lib/c/labcomm.linkscript                     |  4 ++
 lib/c/labcomm_private.h                      |  2 +-
 lib/c/liblabcomm.so                          |  7 +-
 lib/c/test/test_labcomm_generated_encoding.c |  2 +
 7 files changed, 35 insertions(+), 73 deletions(-)

diff --git a/examples/simple/compile.sh b/examples/simple/compile.sh
index 0fcedc1..6fbb8a5 100644
--- a/examples/simple/compile.sh
+++ b/examples/simple/compile.sh
@@ -6,18 +6,12 @@ java -jar ../../compiler/labComm.jar --java=gen --c=gen/simple.c --h=gen/simple.
 
 javac -cp ../../lib/java:. gen/*.java Encoder.java Decoder.java
 
-gcc -Wall -Werror -I . -I ../../lib/c \
-    -DLABCOMM_ENCODER_LINEAR_SEARCH \
-     gen/simple.c  ../../lib/c/labcomm.c \
-    ../../lib/c/labcomm_dynamic_buffer_writer.c \
-    ../../lib/c/labcomm_fd_writer.c \
-    -o example_encoder example_encoder.c 
-gcc -Wall -Werror -I . -I ../../lib/c \
-    -DLABCOMM_ENCODER_LINEAR_SEARCH \
-     gen/simple.c  ../../lib/c/labcomm.c \
-    ../../lib/c/labcomm_dynamic_buffer_writer.c \
-    ../../lib/c/labcomm_fd_reader.c \
-    -o example_decoder example_decoder.c
+gcc -Wall -Werror -I. -I../../lib/c -L../../lib/c \
+    -o example_encoder example_encoder.c gen/simple.c \
+    -llabcomm -Tlabcomm.linkscript
+gcc -Wall -Werror -I . -I ../../lib/c -L../../lib/c \
+    -o example_decoder example_decoder.c gen/simple.c \
+    -llabcomm -Tlabcomm.linkscript
 
 #gcc -o example_encoder -I . -I ../../lib/c example_encoder.c gen/simple.c ../../lib/c/labcomm.c ../../lib/c/labcomm_fd_reader_writer.c
 
diff --git a/lib/c/Makefile b/lib/c/Makefile
index 4dcf336..284ce91 100644
--- a/lib/c/Makefile
+++ b/lib/c/Makefile
@@ -1,10 +1,11 @@
 ## Macros
 
 CC=gcc
-CFLAGS=-g -Wall -Werror -O3  -I. -Itest -DLABCOMM_ENCODER_LINEAR_SEARCH
+#CFLAGS=-g -Wall -Werror -O3  -I. -Itest -DLABCOMM_ENCODER_LINEAR_SEARCH
+CFLAGS=-g -Wall -Werror -O3  -I. -Itest 
 LDFLAGS=-L.
 #LDLIBS_TEST=-Tlabcomm.linkscript  -lcunit -llabcomm
-LDLIBS_TEST=-lcunit -llabcomm
+LDLIBS_TEST=-lcunit -llabcomm -Tlabcomm.linkscript
 
 OBJS= labcomm.o \
       labcomm_dynamic_buffer_writer.o labcomm_fd_reader.o labcomm_fd_writer.o \
diff --git a/lib/c/labcomm.c b/lib/c/labcomm.c
index 9f4f172..6d10055 100644
--- a/lib/c/labcomm.c
+++ b/lib/c/labcomm.c
@@ -28,6 +28,7 @@
 #include <errno.h>
 #include <string.h>
 #include <stdarg.h>
+#include <stddef.h>
 
 #include "labcomm.h"
 #include "labcomm_private.h"
@@ -49,6 +50,7 @@ struct labcomm_encoder {
   struct labcomm_writer *writer;
   struct labcomm_lock *lock;
   labcomm_error_handler_callback on_error;
+  LABCOMM_SIGNATURE_ARRAY_DEF(registered, int);
 };
 
 struct labcomm_sample_entry {
@@ -204,14 +206,13 @@ static int get_encoder_index_by_search(
 
 #else
 
-static int get_encoder_index_by_section(
-  struct labcomm_encoder *e,
+static int get_local_index(
   struct labcomm_signature *s)
 {
   int result = -ENOENT;
-  if (&labcomm_first_signature <= s && s <= &labcomm_last_signature) {
-    //fprintf(stderr, "%d\n", (int)(s - &labcomm_start));
-    result = s - &labcomm_first_signature + LABCOMM_USER;
+
+  if (&labcomm_first_signature <= s && s < &labcomm_last_signature) {
+    result = (int)(s - &labcomm_first_signature) + LABCOMM_USER;
   }
   return result;
 }
@@ -224,7 +225,7 @@ static int get_encoder_index(
 #ifdef LABCOMM_ENCODER_LINEAR_SEARCH
   return get_encoder_index_by_search(e, s);
 #else
-  return get_encoder_index_by_section(e, s);
+  return get_local_index(s);
 #endif
 }
 
@@ -275,51 +276,6 @@ static int encoder_add_signature_by_search(struct labcomm_encoder *e,
 }
 #endif
 
-#ifndef LABCOMM_ENCODER_LINEAR_SEARCH
-static int encoder_add_signature_by_section(struct labcomm_encoder *e,
-					    struct labcomm_signature *s,
-					    labcomm_encoder_function encode)
-{
-  int result = -ENOENT;
-  
-  if (&labcomm_first_signature <= s && s <= &labcomm_last_signature) {
-    /* Signature is in right linker section */
-    struct labcomm_encoder_context *context = e->context;
-    int index = s - &labcomm_first_signature;
-
-    if (context->by_section == NULL) {
-      int n = &labcomm_last_signature - &labcomm_first_signature;
-      context->by_section = malloc(n * sizeof(context->by_section[0]));
-    }
-    if (context->by_section == NULL) {
-      result = -ENOMEM;
-      goto out;
-    }
-    context->by_section[index].next = NULL;
-    context->by_section[index].index = index + LABCOMM_USER;
-    context->by_section[index].signature = s;
-    context->by_section[index].encode = encode;
-    result = context->by_section[index].index;
-  }
-out:
-  return result;
-}
-#endif
-
-static int encoder_add_signature(struct labcomm_encoder *e,
-				  struct labcomm_signature *signature,
-				  labcomm_encoder_function encode)
-{
-  int index = -ENOENT;
-
-#ifdef LABCOMM_ENCODER_LINEAR_SEARCH
-  index = encoder_add_signature_by_search(e, signature, encode);
-#else
-  index = encoder_add_signature_by_section(e, signature, encode);
-#endif
-  return index;
-}
-
 /*
 static struct labcomm_sample_entry *encoder_get_sample_by_signature_address(
   struct labcomm_encoder *encoder,
@@ -363,6 +319,7 @@ struct labcomm_encoder *labcomm_encoder_new(
     result->writer->error = 0;
     result->lock = lock;
     result->on_error = on_error_fprintf;
+    LABCOMM_SIGNATURE_ARRAY_INIT(result->registered, int);
     result->writer->action->alloc(result->writer,result->writer->context,
 				  result, LABCOMM_VERSION);
   }
@@ -375,13 +332,14 @@ void labcomm_internal_encoder_register(
   labcomm_encoder_function encode)
 {
   if (signature->type == LABCOMM_SAMPLE) {
-    if (get_encoder_index(e, signature) == 0) {
-      int index = encoder_add_signature(e, signature, encode);
-      
-      if (index > 0) {
+    int index = get_local_index(signature);
+    if (index > 0) {
+      int *registered = LABCOMM_SIGNATURE_ARRAY_REF(e->registered, int, index);
+      if (! *registered) {
 	struct labcomm_ioctl_register_signature ioctl_data;
 	int err;
-	
+
+	*registered = 1;	
 	ioctl_data.index = index;
 	ioctl_data.signature = signature;	
 	err = labcomm_encoder_ioctl(e, LABCOMM_IOCTL_REGISTER_SIGNATURE,
diff --git a/lib/c/labcomm.linkscript b/lib/c/labcomm.linkscript
index 27cf28f..1e3397a 100644
--- a/lib/c/labcomm.linkscript
+++ b/lib/c/labcomm.linkscript
@@ -1,3 +1,7 @@
+/* Hack to get a link error with (hopefully) useful information if not linked
+   with -Tlabcomm.linkscript */
+"You need to link with '-Tlabcomm.linkscript'"=0;
+
 SECTIONS { 
   labcomm : {
     labcomm_first_signature = ABSOLUTE(.) ;
diff --git a/lib/c/labcomm_private.h b/lib/c/labcomm_private.h
index 9922e1c..975391f 100644
--- a/lib/c/labcomm_private.h
+++ b/lib/c/labcomm_private.h
@@ -42,7 +42,7 @@
  *
  */
 #define LABCOMM_DECLARE_SIGNATURE(name) \
-  struct labcomm_signature __attribute__((section("labcomm"))) name 
+  struct labcomm_signature __attribute__((section("labcomm"),aligned(1))) name 
 
 /*
  * Semi private lock declarations
diff --git a/lib/c/liblabcomm.so b/lib/c/liblabcomm.so
index 3f4a85c..809474e 100644
--- a/lib/c/liblabcomm.so
+++ b/lib/c/liblabcomm.so
@@ -1,2 +1,5 @@
-/*INPUT(liblabcomm.so.1 -ltinfo)*/
-INPUT(liblabcomm.a)
+INPUT(liblabcomm.so.1 -ltinfo)
+/* Hack to get a link error with (hopefully) useful information if not linked
+   with -Tlabcomm.linkscript */
+"You need to link with '-Tlabcomm.linkscript'"+=1;
+/*INPUT(liblabcomm.a)*/
diff --git a/lib/c/test/test_labcomm_generated_encoding.c b/lib/c/test/test_labcomm_generated_encoding.c
index 7de51eb..4e1ff10 100644
--- a/lib/c/test/test_labcomm_generated_encoding.c
+++ b/lib/c/test/test_labcomm_generated_encoding.c
@@ -150,10 +150,12 @@ int main(void)
 
   labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET);
   labcomm_encoder_register_generated_encoding_V(encoder);
+  labcomm_encoder_register_generated_encoding_V(encoder);
   EXPECT({ 0x02, -1, 0x01, 'V', 0x11, 0x00 });
 
   labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET);
   labcomm_encoder_register_generated_encoding_B(encoder);
+  labcomm_encoder_register_generated_encoding_B(encoder);
   EXPECT({0x02, -1, 0x01, 'B', 0x21});
 
   labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET);
-- 
GitLab