Пример #1
0
int test_add_to_same_key(){
  hashtable_t *ht = ht_create( 65536, free_jambo );

  ht_set( ht, "key1", "blorg" );

  ht_set( ht, "key1", "bloff" );
  ht_set( ht, "key1", "gladd" );
  ht_set( ht, "key1", "grutt" );
  ht_set( ht, "key1", "twerky" );
  ht_set( ht, "key1", "lennart" );
  ht_set( ht, "key2", "sverker" );
  ht_set( ht, "key3", "Rogge" );
  ht_set( ht, "key4", "Swutt" );


  check( strcmp( ht_get(ht, "key1"), "lennart") == 0 );
  check( strcmp( ht_get(ht, "key2"), "sverker") == 0);
  check( strcmp( ht_get(ht, "key3"), "Rogge") == 0);
  check( strcmp( ht_get(ht, "key4"), "Swutt") == 0);

  check(ht_size(ht) == 4);

  ht_destroy(ht);

  return 0;
}
void sm_resend(sm_t self, int fd) {
  sm_private_t my = self->private_state;
  sm_sendq_t sendq = ht_get_value(my->fd_to_sendq, HT_KEY(fd));
  while (sendq) {
    char *head = sendq->head;
    char *tail = sendq->tail;
    // send as much as we can without blocking
    sm_on_debug(self, "ss.sendq<%p> resume send to fd=%d len=%zd", sendq, fd,
        (tail - head));
    while (head < tail) {
      ssize_t sent_bytes = send(fd, (void*)head, (tail - head), 0);
      if (sent_bytes <= 0) {
        if (sent_bytes && errno != EWOULDBLOCK) {
          perror("sendq retry failed");
          self->remove_fd(self, fd);
          return;
        }
        break;
      }
      head += sent_bytes;
    }
    sendq->head = head;
    if (head < tail) {
      // still have stuff to send
      sm_on_debug(self, "ss.sendq<%p> defer len=%zd", sendq, (tail - head));
      break;
    }
    self->on_sent(self, fd, sendq->value, sendq->begin, tail - sendq->begin);
    sm_sendq_t nextq = sendq->next;
    ht_put(my->fd_to_sendq, HT_KEY(fd), nextq);
    if (!nextq) {
      FD_CLR(fd, my->send_fds);
    }
    int recv_fd = sendq->recv_fd;
    if (recv_fd && FD_ISSET(recv_fd, my->all_fds)) {
      // if no other sendq's match this blocked recv_fd, re-enable it
      bool found = false;
      if (ht_size(my->fd_to_sendq)) {
        sm_sendq_t *qs = (sm_sendq_t *)ht_values(my->fd_to_sendq);
        sm_sendq_t *q;
        for (q = qs; *q && !found; q++) {
          sm_sendq_t sq;
          for (sq = *q; sq && !found; sq = sq->next) {
            found |= (sq->recv_fd == recv_fd);
          }
        }
        free(qs);
      }
      if (!found) {
        sm_on_debug(self, "ss.sendq<%p> re-enable recv_fd=%d", sendq, recv_fd);
        FD_SET(recv_fd, my->recv_fds);
        // don't FD_SET(tmp_recv_fds), since maybe there was no input
        // instead, let the next select loop pick it up
      }
    }
    sm_on_debug(self, "ss.sendq<%p> free, next=<%p>", sendq, nextq);
    sm_sendq_free(sendq);
    sendq = nextq;
  }
}
sm_status sm_remove_fd(sm_t self, int fd) {
  sm_private_t my = self->private_state;
  if (!FD_ISSET(fd, my->all_fds)) {
    return SM_ERROR;
  }
  void *value = ht_put(my->fd_to_value, HT_KEY(fd), NULL);
  bool is_server = FD_ISSET(fd, my->server_fds);
  sm_on_debug(self, "ss.remove%s_fd(%d)", (is_server ? "_server" : ""), fd);
  sm_status ret = self->on_close(self, fd, value, is_server);
  close(fd);
  FD_CLR(fd, my->all_fds);
  if (is_server) {
    FD_CLR(fd, my->server_fds);
  }
  FD_CLR(fd, my->send_fds);
  FD_CLR(fd, my->recv_fds);
  FD_CLR(fd, my->tmp_send_fds);
  FD_CLR(fd, my->tmp_recv_fds);
  FD_CLR(fd, my->tmp_fail_fds);
  if (fd == my->max_fd) {
    while (my->max_fd >= 0 && !FD_ISSET(my->max_fd, my->all_fds)) {
      my->max_fd--;
    }
  }
  if (ht_size(my->fd_to_sendq)) {
    sm_sendq_t *qs = (sm_sendq_t *)ht_values(my->fd_to_sendq);
    sm_sendq_t *q;
    for (q = qs; *q; q++) {
      sm_sendq_t sendq = *q;
      while (sendq) {
        if (sendq->recv_fd == fd) {
          sendq->recv_fd = 0;
          // don't abort this blocked send, even though the "cause" has ended
        }
        sendq = sendq->next;
      }
    }
    free(qs);
  }
  return ret;
}
Пример #4
0
int main(int argc, char **argv)
{
	struct option long_options[] = {
		// These options don't set a flag
		{"help",                      no_argument,       NULL, 'h'},
		{"alternate",                 no_argument,       NULL, 'A'},
		{"effective",                 required_argument, NULL, 'f'},
		{"duration",                  required_argument, NULL, 'd'},
		{"initial-size",              required_argument, NULL, 'i'},
		{"num-threads",               required_argument, NULL, 'n'},
		{"range",                     required_argument, NULL, 'r'},
		{"seed",                      required_argument, NULL, 's'},
		{"update-rate",               required_argument, NULL, 'u'},
		{"move-rate",                 required_argument, NULL, 'm'},
		{"snapshot-rate",             required_argument, NULL, 'a'},
		{"elasticity",                required_argument, NULL, 'x'},
		{NULL, 0, NULL, 0}
	};
	
	ht_intset_t *set;
	int i, c, size;
	val_t last = 0; 
	val_t val = 0;
	unsigned long reads, effreads, updates, effupds, moves, snapshots, aborts, 
	aborts_locked_read, aborts_locked_write, aborts_validate_read, 
	aborts_validate_write, aborts_validate_commit, aborts_invalid_memory, 
	aborts_double_write,
	max_retries, failures_because_contention;
	thread_data_t *data;
	pthread_t *threads;
	pthread_attr_t attr;
	barrier_t barrier;
	struct timeval start, end;
	struct timespec timeout;
	int duration = DEFAULT_DURATION;
	int initial = DEFAULT_INITIAL;
	int nb_threads = DEFAULT_NB_THREADS;
	long range = DEFAULT_RANGE;
	int seed = DEFAULT_SEED;
	int update = DEFAULT_UPDATE;
	int load_factor = DEFAULT_LOAD;
	int move = DEFAULT_MOVE;
	int snapshot = DEFAULT_SNAPSHOT;
	int unit_tx = DEFAULT_ELASTICITY;
	int alternate = DEFAULT_ALTERNATE;
	int effective = DEFAULT_EFFECTIVE;
	sigset_t block_set;
	
	while(1) {
		i = 0;
		c = getopt_long(argc, argv, "hAf:d:i:n:r:s:u:m:a:l:x:", long_options, &i);
		
		if(c == -1)
			break;
		
		if(c == 0 && long_options[i].flag == 0)
			c = long_options[i].val;
		
		switch(c) {
				case 0:
					// Flag is automatically set 
					break;
				case 'h':
					printf("intset -- STM stress test "
								 "(hash table)\n"
								 "\n"
								 "Usage:\n"
								 "  intset [options...]\n"
								 "\n"
								 "Options:\n"
								 "  -h, --help\n"
								 "        Print this message\n"
								 "  -A, --Alternate\n"
								 "        Consecutive insert/remove target the same value\n"
								 "  -f, --effective <int>\n"
								 "        update txs must effectively write (0=trial, 1=effective, default=" XSTR(DEFAULT_EFFECTIVE) ")\n"
								 "  -d, --duration <int>\n"
								 "        Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n"
								 "  -i, --initial-size <int>\n"
								 "        Number of elements to insert before test (default=" XSTR(DEFAULT_INITIAL) ")\n"
								 "  -n, --num-threads <int>\n"
								 "        Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n"
								 "  -r, --range <int>\n"
								 "        Range of integer values inserted in set (default=" XSTR(DEFAULT_RANGE) ")\n"
								 "  -s, --seed <int>\n"
								 "        RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n"
								 "  -u, --update-rate <int>\n"
								 "        Percentage of update transactions (default=" XSTR(DEFAULT_UPDATE) ")\n"
								 "  -m , --move-rate <int>\n"
								 "        Percentage of move transactions (default=" XSTR(DEFAULT_MOVE) ")\n"
								 "  -a , --snapshot-rate <int>\n"
								 "        Percentage of snapshot transactions (default=" XSTR(DEFAULT_SNAPSHOT) ")\n"
								 "  -l , --load-factor <int>\n"
								 "        Ratio of keys over buckets (default=" XSTR(DEFAULT_LOAD) ")\n"
								 "  -x, --elasticity (default=4)\n"
								 "        Use elastic transactions\n"
								 "        0 = non-protected,\n"
								 "        1 = normal transaction,\n"
								 "        2 = read elastic-tx,\n"
								 "        3 = read/add elastic-tx,\n"
								 "        4 = read/add/rem elastic-tx,\n"
								 "        5 = elastic-tx w/ optimized move.\n"
								 );
					exit(0);
				case 'A':
					alternate = 1;
					break;
				case 'f':
					effective = atoi(optarg);
					break;
				case 'd':
					duration = atoi(optarg);
					break;
				case 'i':
					initial = atoi(optarg);
					break;
				case 'n':
					nb_threads = atoi(optarg);
					break;
				case 'r':
					range = atol(optarg);
					break;
				case 's':
					seed = atoi(optarg);
					break;
				case 'u':
					update = atoi(optarg);
					break;
				case 'm':
					move = atoi(optarg);
					break;
				case 'a':
					snapshot = atoi(optarg);
					break;
				case 'l':
					load_factor = atoi(optarg);
					break;
				case 'x':
					unit_tx = atoi(optarg);
					break;
				case '?':
					printf("Use -h or --help for help\n");
					exit(0);
				default:
					exit(1);
		}
	}
	
	assert(duration >= 0);
	assert(initial >= 0);
	assert(nb_threads > 0);
	assert(range > 0 && range >= initial);
	assert(update >= 0 && update <= 100);
	assert(move >= 0 && move <= update);
	assert(snapshot >= 0 && snapshot <= (100-update));
	assert(initial < MAXHTLENGTH);
	assert(initial >= load_factor);
	
	printf("Set type     : hash table\n");
	printf("Duration     : %d\n", duration);
	printf("Initial size : %d\n", initial);
	printf("Nb threads   : %d\n", nb_threads);
	printf("Value range  : %ld\n", range);
	printf("Seed         : %d\n", seed);
	printf("Update rate  : %d\n", update);
	printf("Load factor  : %d\n", load_factor);
	printf("Move rate    : %d\n", move);
	printf("Snapshot rate: %d\n", snapshot);
	printf("Elasticity   : %d\n", unit_tx);
	printf("Alternate    : %d\n", alternate);	
	printf("Effective    : %d\n", effective);
	printf("Type sizes   : int=%d/long=%d/ptr=%d/word=%d\n",
				 (int)sizeof(int),
				 (int)sizeof(long),
				 (int)sizeof(void *),
				 (int)sizeof(uintptr_t));
	
	timeout.tv_sec = duration / 1000;
	timeout.tv_nsec = (duration % 1000) * 1000000;
	
	if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) {
		perror("malloc");
		exit(1);
	}
	if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) {
		perror("malloc");
		exit(1);
	}
	
	if (seed == 0)
		srand((int)time(0));
	else
		srand(seed);
	
	//maxhtlength = (unsigned int) initial / load_factor;
	set = ht_new();
	
	stop = 0;
	
	// Init STM 
	printf("Initializing STM\n");
	
	TM_STARTUP();
	
	// Populate set 
	printf("Adding %d entries to set\n", initial);
	i = 0;
	maxhtlength = (int) (initial / load_factor);
	while (i < initial) {
		val = rand_range(range);
		if (ht_add(set, val, 0)) {
		  last = val;
		  i++;			
		}
	}
	size = ht_size(set);
	printf("Set size     : %d\n", size);
	printf("Bucket amount: %d\n", maxhtlength);
	printf("Load         : %d\n", load_factor);
	
	// Access set from all threads 
	barrier_init(&barrier, nb_threads + 1);
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	for (i = 0; i < nb_threads; i++) {
		printf("Creating thread %d\n", i);
		data[i].first = last;
		data[i].range = range;
		data[i].update = update;
		data[i].load_factor = load_factor;
		data[i].move = move;
		data[i].snapshot = snapshot;
		data[i].unit_tx = unit_tx;
		data[i].alternate = alternate;
		data[i].effective = effective;
		data[i].nb_add = 0;
		data[i].nb_added = 0;
		data[i].nb_remove = 0;
		data[i].nb_removed = 0;
		data[i].nb_move = 0;
		data[i].nb_moved = 0;
		data[i].nb_snapshot = 0;
		data[i].nb_snapshoted = 0;
		data[i].nb_contains = 0;
		data[i].nb_found = 0;
		data[i].nb_aborts = 0;
		data[i].nb_aborts_locked_read = 0;
		data[i].nb_aborts_locked_write = 0;
		data[i].nb_aborts_validate_read = 0;
		data[i].nb_aborts_validate_write = 0;
		data[i].nb_aborts_validate_commit = 0;
		data[i].nb_aborts_invalid_memory = 0;
		data[i].nb_aborts_double_write = 0;
		data[i].max_retries = 0;
		data[i].seed = rand();
		data[i].set = set;
		data[i].barrier = &barrier;
		data[i].failures_because_contention = 0;
		if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) {
			fprintf(stderr, "Error creating thread\n");
			exit(1);
		}
	}
	pthread_attr_destroy(&attr);
	
	// Start threads 
	barrier_cross(&barrier);
	
	printf("STARTING...\n");
	gettimeofday(&start, NULL);
	if (duration > 0) {
		nanosleep(&timeout, NULL);
	} else {
		sigemptyset(&block_set);
		sigsuspend(&block_set);
	}
	AO_store_full(&stop, 1);
	gettimeofday(&end, NULL);
	printf("STOPPING...\n");
	
	// Wait for thread completion 
	for (i = 0; i < nb_threads; i++) {
		if (pthread_join(threads[i], NULL) != 0) {
			fprintf(stderr, "Error waiting for thread completion\n");
			exit(1);
		}
	}
	duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000);
	aborts = 0;
	aborts_locked_read = 0;
	aborts_locked_write = 0;
	aborts_validate_read = 0;
	aborts_validate_write = 0;
	aborts_validate_commit = 0;
	aborts_invalid_memory = 0;
	aborts_double_write = 0;
	failures_because_contention = 0;
	reads = 0;
	effreads = 0;
	updates = 0;
	effupds = 0;
	moves = 0;
	snapshots = 0;
	max_retries = 0;
	for (i = 0; i < nb_threads; i++) {
		printf("Thread %d\n", i);
		printf("  #add        : %lu\n", data[i].nb_add);
		printf("    #added    : %lu\n", data[i].nb_added);
		printf("  #remove     : %lu\n", data[i].nb_remove);
		printf("    #removed  : %lu\n", data[i].nb_removed);
		printf("  #contains   : %lu\n", data[i].nb_contains);
		printf("  #found      : %lu\n", data[i].nb_found);
		printf("  #move       : %lu\n", data[i].nb_move);
		printf("  #moved      : %lu\n", data[i].nb_moved);
		printf("  #snapshot   : %lu\n", data[i].nb_snapshot);
		printf("  #snapshoted : %lu\n", data[i].nb_snapshoted);
		printf("  #aborts     : %lu\n", data[i].nb_aborts);
		printf("    #lock-r   : %lu\n", data[i].nb_aborts_locked_read);
		printf("    #lock-w   : %lu\n", data[i].nb_aborts_locked_write);
		printf("    #val-r    : %lu\n", data[i].nb_aborts_validate_read);
		printf("    #val-w    : %lu\n", data[i].nb_aborts_validate_write);
		printf("    #val-c    : %lu\n", data[i].nb_aborts_validate_commit);
		printf("    #inv-mem  : %lu\n", data[i].nb_aborts_invalid_memory);
		printf("    #dup-w  : %lu\n", data[i].nb_aborts_double_write);
		printf("    #failures : %lu\n", data[i].failures_because_contention);
		printf("  Max retries : %lu\n", data[i].max_retries);
		aborts += data[i].nb_aborts;
		aborts_locked_read += data[i].nb_aborts_locked_read;
		aborts_locked_write += data[i].nb_aborts_locked_write;
		aborts_validate_read += data[i].nb_aborts_validate_read;
		aborts_validate_write += data[i].nb_aborts_validate_write;
		aborts_validate_commit += data[i].nb_aborts_validate_commit;
		aborts_invalid_memory += data[i].nb_aborts_invalid_memory;
		aborts_double_write += data[i].nb_aborts_double_write;
		failures_because_contention += data[i].failures_because_contention;
		reads += (data[i].nb_contains + data[i].nb_snapshot);
		effreads += data[i].nb_contains + 
		(data[i].nb_add - data[i].nb_added) + 
		(data[i].nb_remove - data[i].nb_removed) + 
		(data[i].nb_move - data[i].nb_moved) +
		data[i].nb_snapshoted;
		updates += (data[i].nb_add + data[i].nb_remove + data[i].nb_move);
		effupds += data[i].nb_removed + data[i].nb_added + data[i].nb_moved; 
		moves += data[i].nb_move;
		snapshots += data[i].nb_snapshot;
		size += data[i].nb_added - data[i].nb_removed;
		if (max_retries < data[i].max_retries)
			max_retries = data[i].max_retries;
	}
	printf("Set size      : %d (expected: %d)\n", ht_size(set), size);
	printf("Duration      : %d (ms)\n", duration);
	printf("#txs          : %lu (%f / s)\n", reads + updates + moves + snapshots, (reads + updates + moves + snapshots) * 1000.0 / duration);
	
	printf("#read txs     : ");
	if (effective) {
		printf("%lu (%f / s)\n", effreads, effreads * 1000.0 / duration);
		printf("  #cont/snpsht: %lu (%f / s)\n", reads, reads * 1000.0 / duration);
	} else printf("%lu (%f / s)\n", reads, reads * 1000.0 / duration);
	
	printf("#eff. upd rate: %f \n", 100.0 * effupds / (effupds + effreads));
	
	printf("#update txs   : ");
	if (effective) {
		printf("%lu (%f / s)\n", effupds, effupds * 1000.0 / duration);
		printf("  #upd trials : %lu (%f / s)\n", updates, updates * 1000.0 / 
					 duration);
	} else printf("%lu (%f / s)\n", updates, updates * 1000.0 / duration);
	
	printf("#move txs     : %lu (%f / s)\n", moves, moves * 1000.0 / duration);
	printf("#snapshot txs : %lu (%f / s)\n", snapshots, snapshots * 1000.0 / duration);
	printf("#aborts       : %lu (%f / s)\n", aborts, aborts * 1000.0 / duration);
	printf("  #lock-r     : %lu (%f / s)\n", aborts_locked_read, aborts_locked_read * 1000.0 / duration);
	printf("  #lock-w     : %lu (%f / s)\n", aborts_locked_write, aborts_locked_write * 1000.0 / duration);
	printf("  #val-r      : %lu (%f / s)\n", aborts_validate_read, aborts_validate_read * 1000.0 / duration);
	printf("  #val-w      : %lu (%f / s)\n", aborts_validate_write, aborts_validate_write * 1000.0 / duration);
	printf("  #val-c      : %lu (%f / s)\n", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration);
	printf("  #inv-mem    : %lu (%f / s)\n", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration);
	printf("  #dup-w      : %lu (%f / s)\n", aborts_double_write, aborts_double_write * 1000.0 / duration);
	printf("  #failures   : %lu\n",  failures_because_contention);
	printf("Max retries   : %lu\n", max_retries);
	
	// Delete set 
	ht_delete(set);
	
	// Cleanup STM 
	TM_SHUTDOWN();
	
	free(threads);
	free(data);
	
	return 0;
}
Пример #5
0
/**
 * Run after gunderscript_build_file() to export the compiled bytecode to an
 * external bytecode file.
 * instance: a Gunderscript object.
 * fileName: The name of the file to export to. Caution: file will be overwritten
 * returns: true upon success, or false if file cannot be opened, 
 * no code has been built, or there was an error building code.
 */
GSAPI bool gunderscript_export_bytecode(Gunderscript * instance, char * fileName) {
  FILE * outFile = fopen(fileName, "w");
  GSByteCodeHeader header;
  HTIter functionHTIter;
  char * byteCodeBuffer;

  /* check if file open fails */
  if(outFile == NULL) {
    instance->err = GUNDERSCRIPTERR_BAD_FILE_OPEN_WRITE;
    return false;
  }

  /* create header */
  strcpy(header.header, GS_BYTECODE_HEADER);
  strcpy(header.buildDate, __DATE__);
  header.byteCodeLen = vm_bytecode_size(instance->vm);
  header.numFunctions = ht_size(vm_functions(instance->vm));

  /* write header to file, return false on failure */
  if(fwrite(&header, sizeof(GSByteCodeHeader), 1, outFile) != 1) {
    instance->err = GUNDERSCRIPTERR_BAD_FILE_WRITE;
    return false;
  }
  
  ht_iter_get(vm_functions(instance->vm), &functionHTIter);

  /* write exported functions to file */
  while(ht_iter_has_next(&functionHTIter)) {
    DSValue value;
    char functionName[GS_MAX_FUNCTION_NAME_LEN];
    size_t functionNameLen;
    char outLen;

    /* get the next item from hashtable */
    ht_iter_next(&functionHTIter, functionName, GS_MAX_FUNCTION_NAME_LEN,
		 &value, &functionNameLen, false);

    /* check if the function should be exported. if so, write it to the file */
    if(((VMFunc*)value.pointerVal)->exported) {

      /* TODO: create an error handler case for this */
      assert(functionNameLen < GS_MAX_FUNCTION_NAME_LEN);
    
      /* write it's name and length to the file */
      outLen = functionNameLen;
      if(fwrite(&outLen, sizeof(char), 1, outFile) != 1 
	 || fwrite(functionName, sizeof(char), functionNameLen, outFile) 
	 != functionNameLen) {
	instance->err = GUNDERSCRIPTERR_BAD_FILE_WRITE;
	return false;
      }

      /* write its CompilerFunc to the file (stores function call information) */
      if(fwrite(value.pointerVal, sizeof(VMFunc), 1, outFile) != 1) {
	instance->err = GUNDERSCRIPTERR_BAD_FILE_WRITE;
	return false;
      }
    }
  }

  byteCodeBuffer = vm_bytecode(instance->vm);
  if(byteCodeBuffer == NULL) {
    instance->err = GUNDERSCRIPTERR_NO_SUCCESSFUL_BUILD;
    return false;
  }

  /* write bytecode */
  if(fwrite(byteCodeBuffer, 
	    vm_bytecode_size(instance->vm), 1, outFile) != 1) {
    instance->err = GUNDERSCRIPTERR_BAD_FILE_WRITE;
    return false;
  }

  fclose(outFile);

  return true;
}
Пример #6
0
/**
 * A parse_function_definitions() subparser that parses the arguments from a function
 * definition. The function then stores the arguments in the current symbol
 * table and returns the number of arguments that were provided.
 * c: an instance of Compiler.
 * l: an instance of lexer.
 * returns: if the current token is a LEXERTYPE_KEYVAR, the parser starts to
 * parse function arguments. If not, it returns -1 and sets c->err to 
 * COMPILERERR_SUCCESS. If an error occurred, or there is a mistake in the
 * script, the function returns -1, but c->err is set to a relevant error code.
 */
static int parse_arguments(Compiler * c, Lexer * l) {

  assert(c != NULL);
  assert(l != NULL);

  /* while the next token is not an end parenthesis and tokens remain, parse
   * the tokens and store each KEYVAR type token in the symbol table as a
   * function argument
   */
  HT * symTbl = symtblstk_peek(c, 0);
  LexerType type;
  size_t len;
  bool prevExisted;
  char * token = lexer_next(l, &type, &len);
  DSValue value;
  int numArgs = 0;

  while(true) {

    /* check current token is an argument, if not throw a fit */
    if(token == NULL || type != LEXERTYPE_KEYVAR) {

      /* if there was a closed parenth, there are no args, otherwise, give err */
      if(tokens_equal(LANG_CPARENTH, LANG_CPARENTH_LEN, token, len)) {
	return 0;
      } else {
	c->err = COMPILERERR_EXPECTED_VARNAME;
	return -1;
      }
    }

    /* store variable along with index at which its data will be stored in the
     * frame stack in the virtual machine
     */
    value.intVal = ht_size(symTbl);
    if(!ht_put_raw_key(symTbl, token, len, 
		       &value, NULL, &prevExisted)) {
      c->err = COMPILERERR_ALLOC_FAILED;
      return -1;
    }
    numArgs++;

    /* check for duplicate var names */
    if(prevExisted) {
      c->err = COMPILERERR_PREV_DEFINED_VAR;
      return -1;
    }

    /* get next token and check for anything but a comma arg delimiter */
    token = lexer_next(l, &type, &len);
    if(!tokens_equal(token, len, LANG_ARGDELIM, LANG_ARGDELIM_LEN)) {

      /* check for end of the args, or invalid token */
      if(tokens_equal(token, len, LANG_CPARENTH, LANG_CPARENTH_LEN)) {
	/* end of args */
	return numArgs;
      } else {
	c->err = COMPILERERR_UNEXPECTED_TOKEN;
	return -1;
      }
    } else {
      /* skip over the comma / arg delimiter */
      token = lexer_next(l, &type, &len);
    }
  }

  return -1;
}
Пример #7
0
int main(int argc, char *argv[])
{
    (void) argc;
    (void) argv;

    hash_table ht;
    ht_init(&ht, HT_KEY_CONST | HT_VALUE_CONST, 0.05);

    char *s1 = (char*)"teststring 1";
    char *s2 = (char*)"teststring 2";
    char *s3 = (char*)"teststring 3";

    ht_insert(&ht, s1, strlen(s1)+1, s2, strlen(s2)+1);

    int contains = ht_contains(&ht, s1, strlen(s1)+1);
    test(contains, "Checking for key \"%s\"", s1);

    size_t value_size;
    char *got = ht_get(&ht, s1, strlen(s1)+1, &value_size);

    fprintf(stderr, "Value size: %zu\n", value_size);
    fprintf(stderr, "Got: {\"%s\": -----\"%s\"}\n", s1, got);

    test(value_size == strlen(s2)+1,
            "Value size was %zu (desired %lu)",
            value_size, strlen(s2)+1);

    fprintf(stderr, "Replacing {\"%s\": \"%s\"} with {\"%s\": \"%s\"}\n", s1, s2, s1, s3);
    ht_insert(&ht, s1, strlen(s1)+1, s3, strlen(s3)+1);

    unsigned int num_keys;
    void **keys;

    keys = ht_keys(&ht, &num_keys);
    test(num_keys == 1, "HashTable has %d keys", num_keys);
    test(keys != NULL, "Keys is not null");
    if(keys)
      free(keys);
    got = ht_get(&ht, s1, strlen(s1)+1, &value_size);

    fprintf(stderr, "Value size: %zu\n", value_size);
    fprintf(stderr, "Got: {\"%s\": \"%s\"}\n", s1, got);

    test(value_size == strlen(s3)+1,
            "Value size was %zu (desired %lu)",
            value_size, strlen(s3)+1);

    fprintf(stderr, "Removing entry with key \"%s\"\n", s1);
    ht_remove(&ht, s1, strlen(s1)+1);

    contains = ht_contains(&ht, s1, strlen(s1)+1);
    test(!contains, "Checking for removal of key \"%s\"", s1);

    keys = ht_keys(&ht, &num_keys);
    test(num_keys == 0, "HashTable has %d keys", num_keys);
    if(keys)
      free(keys);

    fprintf(stderr, "Stress test");
    int key_count = 1000000;
    int i;
    int *many_keys = malloc(key_count * sizeof(*many_keys));
    int *many_values = malloc(key_count * sizeof(*many_values));

    srand(time(NULL));

    for(i = 0; i < key_count; i++)
    {
        many_keys[i] = i;
        many_values[i] = rand();
    }

    struct timespec t1;
    struct timespec t2;

    t1 = snap_time();

    for(i = 0; i < key_count; i++)
    {
        ht_insert(&ht, &(many_keys[i]), sizeof(many_keys[i]), &(many_values[i]), sizeof(many_values[i]));
    }

    t2 = snap_time();

    fprintf(stderr, "Inserting %d keys took %.2f seconds\n", key_count, get_elapsed(t1, t2));
    fprintf(stderr, "Checking inserted keys\n");

    int ok_flag = 1;
    for(i = 0; i < key_count; i++)
    {
        if(ht_contains(&ht, &(many_keys[i]), sizeof(many_keys[i])))
        {
            size_t value_size;
            int value;

            value = *(int*)ht_get(&ht, &(many_keys[i]), sizeof(many_keys[i]), &value_size);

            if(value != many_values[i])
            {
                fprintf(stderr, "Key value mismatch. Got {%d: %d} expected: {%d: %d}\n",
                        many_keys[i], value, many_keys[i], many_values[i]);
                ok_flag = 0;
                break;
            }
        }
        else
        {
            fprintf(stderr, "Missing key-value pair {%d: %d}\n", many_keys[i], many_values[i]);
            ok_flag = 0;
            break;
        }
    }


    test(ok_flag == 1, "Result was %d", ok_flag);
    ht_clear(&ht);
    ht_resize(&ht, 4194304);
    t1 = snap_time();

    for(i = 0; i < key_count; i++)
    {
        ht_insert(&ht, &(many_keys[i]), sizeof(many_keys[i]), &(many_values[i]), sizeof(many_values[i]));
    }

    t2 = snap_time();

    fprintf(stderr, "Inserting %d keys (on preallocated table) took %.2f seconds\n", key_count, get_elapsed(t1, t2));
    for(i = 0; i < key_count; i++)
    {
        ht_remove(&ht, &(many_keys[i]), sizeof(many_keys[i]));
    }
    test(ht_size(&ht) == 0, "%d keys remaining", ht_size(&ht));
    ht_destroy(&ht);
    free(many_keys);
    free(many_values);

    return report_results();
}