예제 #1
0
int spsc_trypop_slot_pass() {
  cqueue_spsc *q;
  int i;
  char data;
  char *p;

  q  = cqueue_spsc_new(26, sizeof(char));
  assert(q);

  // insert dummy data for testing
  for(i=0, data='A'; i < 26; i++, data++) {
    p = cqueue_spsc_trypush_slot(q);
    assert(p);
    *p = data;
    cqueue_spsc_push_slot_finish(q);
  }

  // pop some data so we're not at the start
  for(i=0; i < 13; i++) {
    p = cqueue_spsc_trypop_slot(q);
    assert(p);
    cqueue_spsc_pop_slot_finish(q);
  }

  // check index, used flag, and data
  assert(q->pop_idx == 13);
  void *offset = (char *)(q->array + 12*q->elem_size);
  size_t used = *(size_t *)offset;
  assert(used == 0);
  assert(*p == 'M');

  return 1;
}
예제 #2
0
// initialize each slot in the xmit queue with ethernet header and
// arp data that is consistent between requests and replies
int xmit_queue_init(cqueue_spsc *q, struct in_addr *my_ip,
                    struct ether_addr *my_mac) {
  struct xmit_queue_slot *s;
  struct arp_pkt *arp;
  size_t ether_arp_len, i, start_idx;

  ether_arp_len = sizeof(struct ether_header) + sizeof(struct arp_pkt);
  if (ether_arp_len < ETHER_MIN_LEN - ETHER_CRC_LEN)
    ether_arp_len = ETHER_MIN_LEN - ETHER_CRC_LEN;

  start_idx = q->push_idx;
  for (i=0; i < q->capacity; i++) {
    s = cqueue_spsc_push_slot(q);
    if (!s)
      return 0;

    s->len = ether_arp_len;

    /* ethernet header */
    memcpy(s->ether_h.ether_shost, my_mac, sizeof(struct ether_addr));
    s->ether_h.ether_type = ARP_ETHERTYPE;
    // ether_dhost changes in a request or reply

    /* arp */
    arp = (struct arp_pkt *)s->data;
    arp->arp_h.ar_hrd = ARP_HAF_ETHER;
    arp->arp_h.ar_pro = IP4_ETHERTYPE;
    arp->arp_h.ar_hln = ETHER_ADDR_LEN;
    arp->arp_h.ar_pln = sizeof(struct in_addr);
    // ar_op changes for request/reply
    memcpy(&arp->sha, my_mac, sizeof(struct ether_addr));
    arp->spa.s_addr = my_ip->s_addr;
    // tha and tpa change in a request/reply

    cqueue_spsc_push_slot_finish(q);

    // reset the slot used flag without touching the data
    s = cqueue_spsc_pop_slot(q);
    if (!s)
      return 0;
    cqueue_spsc_pop_slot_finish(q);
  }

  // detect if something else pushed while we were initializing
  if (q->push_idx != start_idx)
    return 0;

  return 1;
}
예제 #3
0
/*!
  Warning: this function relies on internal knowledge of cqueue_spsc
  to optimize num_actions
*/
tqueue *tqueue_new(size_t num_transactions, size_t num_actions) {
  tqueue *q;
  transaction *t;

  size_t transaction_size;

  if (!num_transactions)
    return NULL;

  if (!num_actions)
    return NULL;

  // check overflow
  if (num_actions > (SIZE_MAX - sizeof(transaction)) / sizeof (void *))
    return NULL;
  transaction_size = sizeof(transaction) + num_actions * sizeof(void *);

  q = malloc(sizeof(tqueue));
  if (!q)
    return NULL;

  q->transactions = cqueue_spsc_new(num_transactions, transaction_size);
  if (!q->transactions) {
    free(q);
    return NULL;
  }

  q->num_transactions = num_transactions;
  q->num_actions = (q->transactions->elem_size - sizeof(_Atomic size_t) 
                    - sizeof(transaction)) / sizeof(void *);

  // initialize the transactions
  while ((t = cqueue_spsc_trypush_slot(q->transactions)) != NULL) {
    t->write_idx = 0;
    t->read_idx = 0;
    cqueue_spsc_push_slot_finish(q->transactions);
  }

  while ((t = cqueue_spsc_trypop_slot(q->transactions)) != NULL) {
    cqueue_spsc_pop_slot_finish(q->transactions);
  }

  return q;
}
예제 #4
0
int tqueue_remove(tqueue *q, transaction **tp, void **p) {
  assert(q);

  transaction *t = *tp;

  if (!t) {
    t = cqueue_spsc_trypop_slot(q->transactions);
    if (!t)  // transaction queue empty
      return TQUEUE_EMPTY;
  }

  *p = t->actions[t->read_idx];
  t->read_idx++;

  if (t->read_idx == t->write_idx) { // we've read everything
    t->write_idx = 0;
    t->read_idx = 0;
    t = NULL;
    cqueue_spsc_pop_slot_finish(q->transactions);
    return TQUEUE_TRANSACTION_EMPTY;
  }

  return TQUEUE_SUCCESS;
}