diff src/c/urweb.c @ 2206:c1a62ce47083

Merge.
author Ziv Scully <ziv@mit.edu>
date Tue, 27 May 2014 21:38:01 -0400
parents 01c8aceac480 4a93f379c452
children cb74460f046a
line wrap: on
line diff
--- a/src/c/urweb.c	Tue May 27 21:15:53 2014 -0400
+++ b/src/c/urweb.c	Tue May 27 21:38:01 2014 -0400
@@ -460,8 +460,7 @@
 
   void *client_data;
 
-  void *logger_data;
-  uw_logger log_debug;
+  uw_loggers *loggers;
 
   int isPost, hasPostBody;
   uw_Basis_postBody postBody;
@@ -487,7 +486,7 @@
 size_t uw_heap_max = SIZE_MAX;
 size_t uw_script_max = SIZE_MAX;
 
-uw_context uw_init(int id, void *logger_data, uw_logger log_debug) {
+uw_context uw_init(int id, uw_loggers *lg) {
   uw_context ctx = malloc(sizeof(struct uw_context));
 
   ctx->app = NULL;
@@ -546,8 +545,7 @@
 
   ctx->client_data = uw_init_client_data();
 
-  ctx->logger_data = logger_data;
-  ctx->log_debug = log_debug;
+  ctx->loggers = lg;
 
   ctx->isPost = ctx->hasPostBody = 0;
 
@@ -601,6 +599,11 @@
   return ctx->db;
 }
 
+
+uw_loggers* uw_get_loggers(struct uw_context *ctx) {
+  return ctx->loggers;
+}
+
 void uw_free(uw_context ctx) {
   size_t i;
 
@@ -1258,17 +1261,34 @@
   ctx->amInitializing = 0;
 }
 
+static void align_heap(uw_context ctx) {
+  size_t posn = ctx->heap.front - ctx->heap.start;
+
+  if (posn % 4 != 0) {
+    size_t bump = 4 - posn % 4;
+    uw_check_heap(ctx, bump);
+    ctx->heap.front += bump;
+  }
+}
+
 void *uw_malloc(uw_context ctx, size_t len) {
+  // On some architectures, it's important that all word-sized memory accesses
+  // be to word-aligned addresses, so we'll do a little bit of extra work here
+  // in anticipation of a possible word-aligned access to the address we'll
+  // return.
+
   void *result;
 
   if (ctx->amInitializing) {
-    result = malloc(len);
-
-    if (result)
+    int error = posix_memalign(&result, 4, len);
+
+    if (!error)
       return result;
     else
-      uw_error(ctx, FATAL, "uw_malloc: malloc() returns 0");
+      uw_error(ctx, FATAL, "uw_malloc: posix_memalign() returns %d", error);
   } else {
+    align_heap(ctx);
+
     uw_check_heap(ctx, len);
 
     result = ctx->heap.front;
@@ -1278,6 +1298,8 @@
 }
 
 void uw_begin_region(uw_context ctx) {
+  align_heap(ctx);
+
   regions *r = (regions *) ctx->heap.front;
 
   uw_check_heap(ctx, sizeof(regions));
@@ -1588,6 +1610,9 @@
   int len;
   size_t s_len = strlen(s);
 
+  if(ctx->id < 0)
+    uw_error(ctx, FATAL, "Attempt to create client source using inappropriate context");
+
   uw_check_script(ctx, 15 + 2 * INTS_MAX + s_len);
   sprintf(ctx->script.front, "s%d_%llu=sc(exec(%n", ctx->id, ctx->source_count, &len);
   ctx->script.front += len;
@@ -3316,32 +3341,58 @@
         }
       }
 
+  if (ctx->transaction_started) {
+    int code = ctx->app->db_commit(ctx);
+
+    if (code) {
+      if (ctx->client)
+        release_client(ctx->client);
+
+      if (code == -1) {
+        // This case is for a serialization failure, which is not really an "error."
+        // The transaction will restart, so we should rollback any transactionals
+        // that triggered above.
+
+        for (i = ctx->used_transactionals-1; i >= 0; --i)
+          if (ctx->transactionals[i].rollback != NULL)
+            ctx->transactionals[i].rollback(ctx->transactionals[i].data);
+
+        for (i = ctx->used_transactionals-1; i >= 0; --i)
+          if (ctx->transactionals[i].free)
+            ctx->transactionals[i].free(ctx->transactionals[i].data, 1);
+
+	return 1;
+      }
+
+      for (i = ctx->used_transactionals-1; i >= 0; --i)
+        if (ctx->transactionals[i].free)
+          ctx->transactionals[i].free(ctx->transactionals[i].data, 0);
+
+      uw_set_error_message(ctx, "Error running SQL COMMIT");
+      return 0;
+    }
+  }
+
   for (i = ctx->used_transactionals-1; i >= 0; --i)
     if (ctx->transactionals[i].rollback == NULL)
       if (ctx->transactionals[i].commit) {
         ctx->transactionals[i].commit(ctx->transactionals[i].data);
         if (uw_has_error(ctx)) {
-          uw_rollback(ctx, 0);
+           if (ctx->client)
+             release_client(ctx->client);
+
+           for (i = ctx->used_transactionals-1; i >= 0; --i)
+             if (ctx->transactionals[i].rollback != NULL)
+               ctx->transactionals[i].rollback(ctx->transactionals[i].data);
+
+           for (i = ctx->used_transactionals-1; i >= 0; --i)
+             if (ctx->transactionals[i].free)
+               ctx->transactionals[i].free(ctx->transactionals[i].data, 0);
+
           return 0;
         }
       }
 
-  if (ctx->transaction_started) {
-    int code = ctx->app->db_commit(ctx);
-
-    if (code) {
-      if (code == -1)
-	return 1;
-
-      for (i = ctx->used_transactionals-1; i >= 0; --i)
-	if (ctx->transactionals[i].free)
-	  ctx->transactionals[i].free(ctx->transactionals[i].data, 0);
-
-      uw_set_error_message(ctx, "Error running SQL COMMIT");
-      return 0;
-    }
-  }
-
   for (i = 0; i < ctx->used_deltas; ++i) {
     delta *d = &ctx->deltas[i];
     client *c = find_client(d->client);
@@ -3455,11 +3506,12 @@
 
 size_t uw_transactionals_max = SIZE_MAX;
 
-void uw_register_transactional(uw_context ctx, void *data, uw_callback commit, uw_callback rollback,
+int uw_register_transactional(uw_context ctx, void *data, uw_callback commit, uw_callback rollback,
                                uw_callback_with_retry free) {
   if (ctx->used_transactionals >= ctx->n_transactionals) {
     if (ctx->used_transactionals+1 > uw_transactionals_max)
-      uw_error(ctx, FATAL, "Exceeded limit on number of transactionals");
+      // Exceeded limit on number of transactionals.
+      return -1;
     ctx->transactionals = realloc(ctx->transactionals, sizeof(transactional) * (ctx->used_transactionals+1));
     ++ctx->n_transactionals;
   }
@@ -3468,6 +3520,8 @@
   ctx->transactionals[ctx->used_transactionals].commit = commit;
   ctx->transactionals[ctx->used_transactionals].rollback = rollback;
   ctx->transactionals[ctx->used_transactionals++].free = free;
+
+  return 0;
 }
 
 
@@ -3965,7 +4019,8 @@
 
 uw_Basis_time uw_Basis_fromDatetime(uw_context ctx, uw_Basis_int year, uw_Basis_int month, uw_Basis_int day, uw_Basis_int hour, uw_Basis_int minute, uw_Basis_int second) {
   struct tm tm = { .tm_year = year - 1900, .tm_mon = month, .tm_mday = day,
-                   .tm_hour = hour, .tm_min = minute, .tm_sec = second };
+                   .tm_hour = hour, .tm_min = minute, .tm_sec = second,
+                   .tm_isdst = -1 };
   uw_Basis_time r = { timelocal(&tm) };
   return r;
 }
@@ -4136,8 +4191,8 @@
 }
 
 uw_Basis_unit uw_Basis_debug(uw_context ctx, uw_Basis_string s) {
-  if (ctx->log_debug)
-    ctx->log_debug(ctx->logger_data, "%s\n", s);
+  if (ctx->loggers->log_debug)
+    ctx->loggers->log_debug(ctx->loggers->logger_data, "%s\n", s);
   else
     fprintf(stderr, "%s\n", s);
   return uw_unit_v;
@@ -4379,3 +4434,13 @@
 
   return f;
 }
+
+uw_Basis_string uw_Basis_blessData(uw_context ctx, uw_Basis_string s) {
+  char *p = s;
+
+  for (; *p; ++p)
+    if (!isalnum(*p) && *p != '-' && *p != '_')
+      uw_error(ctx, FATAL, "Illegal HTML5 data-* attribute: %s", s);
+
+  return s;
+}