Mercurial > urweb
comparison 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 |
comparison
equal
deleted
inserted
replaced
2205:cdea39473c78 | 2206:c1a62ce47083 |
---|---|
458 | 458 |
459 int deadline; | 459 int deadline; |
460 | 460 |
461 void *client_data; | 461 void *client_data; |
462 | 462 |
463 void *logger_data; | 463 uw_loggers *loggers; |
464 uw_logger log_debug; | |
465 | 464 |
466 int isPost, hasPostBody; | 465 int isPost, hasPostBody; |
467 uw_Basis_postBody postBody; | 466 uw_Basis_postBody postBody; |
468 uw_Basis_string queryString; | 467 uw_Basis_string queryString; |
469 | 468 |
485 size_t uw_headers_max = SIZE_MAX; | 484 size_t uw_headers_max = SIZE_MAX; |
486 size_t uw_page_max = SIZE_MAX; | 485 size_t uw_page_max = SIZE_MAX; |
487 size_t uw_heap_max = SIZE_MAX; | 486 size_t uw_heap_max = SIZE_MAX; |
488 size_t uw_script_max = SIZE_MAX; | 487 size_t uw_script_max = SIZE_MAX; |
489 | 488 |
490 uw_context uw_init(int id, void *logger_data, uw_logger log_debug) { | 489 uw_context uw_init(int id, uw_loggers *lg) { |
491 uw_context ctx = malloc(sizeof(struct uw_context)); | 490 uw_context ctx = malloc(sizeof(struct uw_context)); |
492 | 491 |
493 ctx->app = NULL; | 492 ctx->app = NULL; |
494 ctx->id = id; | 493 ctx->id = id; |
495 | 494 |
544 | 543 |
545 ctx->deadline = INT_MAX; | 544 ctx->deadline = INT_MAX; |
546 | 545 |
547 ctx->client_data = uw_init_client_data(); | 546 ctx->client_data = uw_init_client_data(); |
548 | 547 |
549 ctx->logger_data = logger_data; | 548 ctx->loggers = lg; |
550 ctx->log_debug = log_debug; | |
551 | 549 |
552 ctx->isPost = ctx->hasPostBody = 0; | 550 ctx->isPost = ctx->hasPostBody = 0; |
553 | 551 |
554 ctx->queryString = NULL; | 552 ctx->queryString = NULL; |
555 | 553 |
597 ctx->db = db; | 595 ctx->db = db; |
598 } | 596 } |
599 | 597 |
600 void *uw_get_db(uw_context ctx) { | 598 void *uw_get_db(uw_context ctx) { |
601 return ctx->db; | 599 return ctx->db; |
600 } | |
601 | |
602 | |
603 uw_loggers* uw_get_loggers(struct uw_context *ctx) { | |
604 return ctx->loggers; | |
602 } | 605 } |
603 | 606 |
604 void uw_free(uw_context ctx) { | 607 void uw_free(uw_context ctx) { |
605 size_t i; | 608 size_t i; |
606 | 609 |
1256 | 1259 |
1257 void uw_end_initializing(uw_context ctx) { | 1260 void uw_end_initializing(uw_context ctx) { |
1258 ctx->amInitializing = 0; | 1261 ctx->amInitializing = 0; |
1259 } | 1262 } |
1260 | 1263 |
1264 static void align_heap(uw_context ctx) { | |
1265 size_t posn = ctx->heap.front - ctx->heap.start; | |
1266 | |
1267 if (posn % 4 != 0) { | |
1268 size_t bump = 4 - posn % 4; | |
1269 uw_check_heap(ctx, bump); | |
1270 ctx->heap.front += bump; | |
1271 } | |
1272 } | |
1273 | |
1261 void *uw_malloc(uw_context ctx, size_t len) { | 1274 void *uw_malloc(uw_context ctx, size_t len) { |
1275 // On some architectures, it's important that all word-sized memory accesses | |
1276 // be to word-aligned addresses, so we'll do a little bit of extra work here | |
1277 // in anticipation of a possible word-aligned access to the address we'll | |
1278 // return. | |
1279 | |
1262 void *result; | 1280 void *result; |
1263 | 1281 |
1264 if (ctx->amInitializing) { | 1282 if (ctx->amInitializing) { |
1265 result = malloc(len); | 1283 int error = posix_memalign(&result, 4, len); |
1266 | 1284 |
1267 if (result) | 1285 if (!error) |
1268 return result; | 1286 return result; |
1269 else | 1287 else |
1270 uw_error(ctx, FATAL, "uw_malloc: malloc() returns 0"); | 1288 uw_error(ctx, FATAL, "uw_malloc: posix_memalign() returns %d", error); |
1271 } else { | 1289 } else { |
1290 align_heap(ctx); | |
1291 | |
1272 uw_check_heap(ctx, len); | 1292 uw_check_heap(ctx, len); |
1273 | 1293 |
1274 result = ctx->heap.front; | 1294 result = ctx->heap.front; |
1275 ctx->heap.front += len; | 1295 ctx->heap.front += len; |
1276 return result; | 1296 return result; |
1277 } | 1297 } |
1278 } | 1298 } |
1279 | 1299 |
1280 void uw_begin_region(uw_context ctx) { | 1300 void uw_begin_region(uw_context ctx) { |
1301 align_heap(ctx); | |
1302 | |
1281 regions *r = (regions *) ctx->heap.front; | 1303 regions *r = (regions *) ctx->heap.front; |
1282 | 1304 |
1283 uw_check_heap(ctx, sizeof(regions)); | 1305 uw_check_heap(ctx, sizeof(regions)); |
1284 | 1306 |
1285 ctx->heap.front += sizeof(regions); | 1307 ctx->heap.front += sizeof(regions); |
1585 } | 1607 } |
1586 | 1608 |
1587 uw_Basis_source uw_Basis_new_client_source(uw_context ctx, uw_Basis_string s) { | 1609 uw_Basis_source uw_Basis_new_client_source(uw_context ctx, uw_Basis_string s) { |
1588 int len; | 1610 int len; |
1589 size_t s_len = strlen(s); | 1611 size_t s_len = strlen(s); |
1612 | |
1613 if(ctx->id < 0) | |
1614 uw_error(ctx, FATAL, "Attempt to create client source using inappropriate context"); | |
1590 | 1615 |
1591 uw_check_script(ctx, 15 + 2 * INTS_MAX + s_len); | 1616 uw_check_script(ctx, 15 + 2 * INTS_MAX + s_len); |
1592 sprintf(ctx->script.front, "s%d_%llu=sc(exec(%n", ctx->id, ctx->source_count, &len); | 1617 sprintf(ctx->script.front, "s%d_%llu=sc(exec(%n", ctx->id, ctx->source_count, &len); |
1593 ctx->script.front += len; | 1618 ctx->script.front += len; |
1594 strcpy(ctx->script.front, s); | 1619 strcpy(ctx->script.front, s); |
3314 uw_rollback(ctx, 0); | 3339 uw_rollback(ctx, 0); |
3315 return 0; | 3340 return 0; |
3316 } | 3341 } |
3317 } | 3342 } |
3318 | 3343 |
3344 if (ctx->transaction_started) { | |
3345 int code = ctx->app->db_commit(ctx); | |
3346 | |
3347 if (code) { | |
3348 if (ctx->client) | |
3349 release_client(ctx->client); | |
3350 | |
3351 if (code == -1) { | |
3352 // This case is for a serialization failure, which is not really an "error." | |
3353 // The transaction will restart, so we should rollback any transactionals | |
3354 // that triggered above. | |
3355 | |
3356 for (i = ctx->used_transactionals-1; i >= 0; --i) | |
3357 if (ctx->transactionals[i].rollback != NULL) | |
3358 ctx->transactionals[i].rollback(ctx->transactionals[i].data); | |
3359 | |
3360 for (i = ctx->used_transactionals-1; i >= 0; --i) | |
3361 if (ctx->transactionals[i].free) | |
3362 ctx->transactionals[i].free(ctx->transactionals[i].data, 1); | |
3363 | |
3364 return 1; | |
3365 } | |
3366 | |
3367 for (i = ctx->used_transactionals-1; i >= 0; --i) | |
3368 if (ctx->transactionals[i].free) | |
3369 ctx->transactionals[i].free(ctx->transactionals[i].data, 0); | |
3370 | |
3371 uw_set_error_message(ctx, "Error running SQL COMMIT"); | |
3372 return 0; | |
3373 } | |
3374 } | |
3375 | |
3319 for (i = ctx->used_transactionals-1; i >= 0; --i) | 3376 for (i = ctx->used_transactionals-1; i >= 0; --i) |
3320 if (ctx->transactionals[i].rollback == NULL) | 3377 if (ctx->transactionals[i].rollback == NULL) |
3321 if (ctx->transactionals[i].commit) { | 3378 if (ctx->transactionals[i].commit) { |
3322 ctx->transactionals[i].commit(ctx->transactionals[i].data); | 3379 ctx->transactionals[i].commit(ctx->transactionals[i].data); |
3323 if (uw_has_error(ctx)) { | 3380 if (uw_has_error(ctx)) { |
3324 uw_rollback(ctx, 0); | 3381 if (ctx->client) |
3382 release_client(ctx->client); | |
3383 | |
3384 for (i = ctx->used_transactionals-1; i >= 0; --i) | |
3385 if (ctx->transactionals[i].rollback != NULL) | |
3386 ctx->transactionals[i].rollback(ctx->transactionals[i].data); | |
3387 | |
3388 for (i = ctx->used_transactionals-1; i >= 0; --i) | |
3389 if (ctx->transactionals[i].free) | |
3390 ctx->transactionals[i].free(ctx->transactionals[i].data, 0); | |
3391 | |
3325 return 0; | 3392 return 0; |
3326 } | 3393 } |
3327 } | 3394 } |
3328 | |
3329 if (ctx->transaction_started) { | |
3330 int code = ctx->app->db_commit(ctx); | |
3331 | |
3332 if (code) { | |
3333 if (code == -1) | |
3334 return 1; | |
3335 | |
3336 for (i = ctx->used_transactionals-1; i >= 0; --i) | |
3337 if (ctx->transactionals[i].free) | |
3338 ctx->transactionals[i].free(ctx->transactionals[i].data, 0); | |
3339 | |
3340 uw_set_error_message(ctx, "Error running SQL COMMIT"); | |
3341 return 0; | |
3342 } | |
3343 } | |
3344 | 3395 |
3345 for (i = 0; i < ctx->used_deltas; ++i) { | 3396 for (i = 0; i < ctx->used_deltas; ++i) { |
3346 delta *d = &ctx->deltas[i]; | 3397 delta *d = &ctx->deltas[i]; |
3347 client *c = find_client(d->client); | 3398 client *c = find_client(d->client); |
3348 | 3399 |
3453 } | 3504 } |
3454 | 3505 |
3455 | 3506 |
3456 size_t uw_transactionals_max = SIZE_MAX; | 3507 size_t uw_transactionals_max = SIZE_MAX; |
3457 | 3508 |
3458 void uw_register_transactional(uw_context ctx, void *data, uw_callback commit, uw_callback rollback, | 3509 int uw_register_transactional(uw_context ctx, void *data, uw_callback commit, uw_callback rollback, |
3459 uw_callback_with_retry free) { | 3510 uw_callback_with_retry free) { |
3460 if (ctx->used_transactionals >= ctx->n_transactionals) { | 3511 if (ctx->used_transactionals >= ctx->n_transactionals) { |
3461 if (ctx->used_transactionals+1 > uw_transactionals_max) | 3512 if (ctx->used_transactionals+1 > uw_transactionals_max) |
3462 uw_error(ctx, FATAL, "Exceeded limit on number of transactionals"); | 3513 // Exceeded limit on number of transactionals. |
3514 return -1; | |
3463 ctx->transactionals = realloc(ctx->transactionals, sizeof(transactional) * (ctx->used_transactionals+1)); | 3515 ctx->transactionals = realloc(ctx->transactionals, sizeof(transactional) * (ctx->used_transactionals+1)); |
3464 ++ctx->n_transactionals; | 3516 ++ctx->n_transactionals; |
3465 } | 3517 } |
3466 | 3518 |
3467 ctx->transactionals[ctx->used_transactionals].data = data; | 3519 ctx->transactionals[ctx->used_transactionals].data = data; |
3468 ctx->transactionals[ctx->used_transactionals].commit = commit; | 3520 ctx->transactionals[ctx->used_transactionals].commit = commit; |
3469 ctx->transactionals[ctx->used_transactionals].rollback = rollback; | 3521 ctx->transactionals[ctx->used_transactionals].rollback = rollback; |
3470 ctx->transactionals[ctx->used_transactionals++].free = free; | 3522 ctx->transactionals[ctx->used_transactionals++].free = free; |
3523 | |
3524 return 0; | |
3471 } | 3525 } |
3472 | 3526 |
3473 | 3527 |
3474 // "Garbage collection" | 3528 // "Garbage collection" |
3475 | 3529 |
3963 return tm.seconds; | 4017 return tm.seconds; |
3964 } | 4018 } |
3965 | 4019 |
3966 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) { | 4020 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) { |
3967 struct tm tm = { .tm_year = year - 1900, .tm_mon = month, .tm_mday = day, | 4021 struct tm tm = { .tm_year = year - 1900, .tm_mon = month, .tm_mday = day, |
3968 .tm_hour = hour, .tm_min = minute, .tm_sec = second }; | 4022 .tm_hour = hour, .tm_min = minute, .tm_sec = second, |
4023 .tm_isdst = -1 }; | |
3969 uw_Basis_time r = { timelocal(&tm) }; | 4024 uw_Basis_time r = { timelocal(&tm) }; |
3970 return r; | 4025 return r; |
3971 } | 4026 } |
3972 | 4027 |
3973 uw_Basis_int uw_Basis_datetimeYear(uw_context ctx, uw_Basis_time time) { | 4028 uw_Basis_int uw_Basis_datetimeYear(uw_context ctx, uw_Basis_time time) { |
4134 fprintf(stderr, "%s\n", s); | 4189 fprintf(stderr, "%s\n", s); |
4135 return 0; | 4190 return 0; |
4136 } | 4191 } |
4137 | 4192 |
4138 uw_Basis_unit uw_Basis_debug(uw_context ctx, uw_Basis_string s) { | 4193 uw_Basis_unit uw_Basis_debug(uw_context ctx, uw_Basis_string s) { |
4139 if (ctx->log_debug) | 4194 if (ctx->loggers->log_debug) |
4140 ctx->log_debug(ctx->logger_data, "%s\n", s); | 4195 ctx->loggers->log_debug(ctx->loggers->logger_data, "%s\n", s); |
4141 else | 4196 else |
4142 fprintf(stderr, "%s\n", s); | 4197 fprintf(stderr, "%s\n", s); |
4143 return uw_unit_v; | 4198 return uw_unit_v; |
4144 } | 4199 } |
4145 | 4200 |
4377 uw_error(ctx, FATAL, "firstFormField: Missing null terminator"); | 4432 uw_error(ctx, FATAL, "firstFormField: Missing null terminator"); |
4378 f->remaining = s+1; | 4433 f->remaining = s+1; |
4379 | 4434 |
4380 return f; | 4435 return f; |
4381 } | 4436 } |
4437 | |
4438 uw_Basis_string uw_Basis_blessData(uw_context ctx, uw_Basis_string s) { | |
4439 char *p = s; | |
4440 | |
4441 for (; *p; ++p) | |
4442 if (!isalnum(*p) && *p != '-' && *p != '_') | |
4443 uw_error(ctx, FATAL, "Illegal HTML5 data-* attribute: %s", s); | |
4444 | |
4445 return s; | |
4446 } |