uint64_t* consume_transport() { DEBUG( static uint64_t counter = 0 ); register uint64_t node_sequence = ((*node_sequence_ptr) & MASK); walker = (volatile uint64_t**)follow_sequence_ptr; do { DEBUGVV( printf( "consume_transport:\tWaiting on node %d to release %d [%d]\n", \ *follow, node_sequence, (**walker) & MASK ) ); while(node_sequence == ( (**walker) & MASK ) ) sched_yield(); } while( *(++walker) ); DEBUGVV( printf( "consume_transport:\tMessage %d consumed from slot %d\n", \ ring[ node_sequence ].data.value, node_sequence ) ); DEBUG( *get_counter_ptr = ++counter ); DEBUG( *fad_value_ptr = *fed_value_ptr / counter ); DEBUGV( if( !( counter & DEBUG_SKIP_MASK ) ) \ printf( "Ctr: %dm\tFed: %d\n", counter/DEBUG_SKIP_MASK, *fad_value_ptr ) ); DEBUG( if( counter == 100 + RING_ENTRY_COUNT ) *fed_value_ptr = 0 ); return &ring[ node_sequence ].data.value; }
/* Get a free binary buffer, first invalidating it in the receive * queue if necessary. In practice all buffers should be used * before they are invalidated, if BUFFERS_PER_SLAVE is large enough. * slave_lock is held on both entry and exit of this function. */ static void * get_free_buf(struct slave_state *sstate) { int newest = (sstate->newest_buf + 1) & (BUFFERS_PER_SLAVE - 1); sstate->newest_buf = newest; void *buf = sstate->b[newest].buf; if (DEBUGVV(7)) { char b[1024]; snprintf(b, sizeof(b), "get free %d index %d buf=%p age %d qlength %d\n", newest, sstate->b[newest].queue_index, buf, queue_age, queue_length); logline(&sstate->client, "? ", b); } int index = sstate->b[newest].queue_index; if (index < 0) return buf; /* Invalidate the buffer if the calling thread still owns its previous * entry in the receive queue. The entry may have been overwritten by * another thread, but only after a new move which invalidates the * entire receive queue. */ if (receive_queue[index] && receive_queue[index]->owner == sstate->thread_id) { receive_queue[index] = NULL; } sstate->b[newest].queue_index = -1; return buf; }
void release_transport() { DEBUG( static uint64_t counter = 0 ); DEBUGVV( register uint64_t node_sequence = ((*node_sequence_ptr) & MASK) ); DEBUGVV( printf( "release_transport:\tmessage %d released from slot %d\n", \ ring[ node_sequence ].data.value, node_sequence ) ); DEBUGVV( printf( "release_transport:\tMoving node sequence number from %d to %d\n", ((*node_sequence_ptr) & MASK), (((*node_sequence_ptr) + 1) & MASK) ) ); BARRIER; ++(*node_sequence_ptr); DEBUG( *put_counter_ptr = ++counter ); DEBUG( *bad_value_ptr = *bed_value_ptr / counter ); DEBUGV( if( !( counter & DEBUG_SKIP_MASK ) ) \ printf( "Ctr: %dm\tBed: %d\n", counter/DEBUG_SKIP_MASK, *bad_value_ptr ) ); DEBUG( if( counter == 100 + RING_ENTRY_COUNT ) *bed_value_ptr = 0 ); }
/* Get a reply to one gtp command. Return the gtp command id, * or -1 if error. reply must have at least CMDS_SIZE bytes. * The ascii reply ends with an empty line; if the first line * contains "@size", a binary reply of size bytes follows the * empty line. @size is not standard gtp, it is only used * internally by Pachi for the genmoves command; it must be the * last parameter on the line. * *bin_size is the maximum size upon entry, actual size on return. * slave_lock is not held on either entry or exit of this function. */ static int get_reply(FILE *f, struct in_addr client, char *reply, void *bin_reply, int *bin_size) { double start = time_now(); int reply_id = -1; *reply = '\0'; if (!fgets(reply, CMDS_SIZE, f)) return -1; /* Check for binary reply. */ char *s = strchr(reply, '@'); int size = 0; if (s) size = atoi(s+1); assert(size <= *bin_size); *bin_size = size; if (DEBUGV(s, 2)) logline(&client, "<<", reply); if ((*reply == '=' || *reply == '?') && isdigit(reply[1])) reply_id = atoi(reply+1); /* Read the rest of the ascii reply */ char *line = reply + strlen(reply); while (fgets(line, reply + CMDS_SIZE - line, f) && *line != '\n') { if (DEBUGL(3)) logline(&client, "<<", line); line += strlen(line); } if (*line != '\n') return -1; /* Read the binary reply if any. */ int len; while (size && (len = fread(bin_reply, 1, size, f)) > 0) { bin_reply = (char *)bin_reply + len; size -= len; } if (*bin_size && DEBUGVV(2)) { char buf[1024]; snprintf(buf, sizeof(buf), "read reply %d+%d bytes in %.4fms\n", (int)strlen(reply), *bin_size, (time_now() - start)*1000); logline(&client, "= ", buf); } return size ? -1 : reply_id; }
/* Insert a buffer in the receive queue. It should be the most * recent buffer allocated by the calling thread. * slave_lock is held on both entry and exit of this function. */ static void insert_buf(struct slave_state *sstate, void *buf, int size) { assert(queue_length < queue_max_length); int newest = sstate->newest_buf; assert(buf == sstate->b[newest].buf); /* Update the buffer if necessary before making it * available to other threads. */ if (sstate->insert_hook) sstate->insert_hook(buf, size); if (DEBUGVV(7)) { char b[1024]; snprintf(b, sizeof(b), "insert newest %d age %d rq[%d]->%p owner %d\n", newest, queue_age, queue_length, buf, sstate->thread_id); logline(&sstate->client, "? ", b); } receive_queue[queue_length] = &sstate->b[newest]; receive_queue[queue_length]->size = size; receive_queue[queue_length]->queue_index = queue_length; queue_length++; }