예제 #1
0
파일: pong61.c 프로젝트: cs61/cs61-psets
// pong_thread(threadarg)
//    Connect to the server at the position indicated by `threadarg`
//    (which is a pointer to a `pong_args` structure).
void* pong_thread(void* threadarg) {
    pthread_detach(pthread_self());

    // Copy thread arguments onto our stack.
    pong_args pa = *((pong_args*) threadarg);

    char url[256];
    snprintf(url, sizeof(url), "move?x=%d&y=%d&style=on",
             pa.x, pa.y);

    http_connection* conn = http_connect(pong_addr);
    http_send_request(conn, url);
    http_receive_response_headers(conn);
    if (conn->status_code != 200)
        fprintf(stderr, "%.3f sec: warning: %d,%d: "
                "server returned status %d (expected 200)\n",
                elapsed(), pa.x, pa.y, conn->status_code);

    http_receive_response_body(conn);
    double result = strtod(conn->buf, NULL);
    if (result < 0) {
        fprintf(stderr, "%.3f sec: server returned error: %s\n",
                elapsed(), http_truncate_response(conn));
        exit(1);
    }

    http_close(conn);

    // signal the main thread to continue
    pthread_cond_signal(&condvar);
    // and exit!
    pthread_exit(NULL);
}
예제 #2
0
파일: pong61.c 프로젝트: cs61/cs61-psets
// main(argc, argv)
//    The main loop.
int main(int argc, char** argv) {
    // parse arguments
    int ch, nocheck = 0;
    while ((ch = getopt(argc, argv, "nh:p:u:")) != -1) {
        if (ch == 'h')
            pong_host = optarg;
        else if (ch == 'p')
            pong_port = optarg;
        else if (ch == 'u')
            pong_user = optarg;
        else if (ch == 'n')
            nocheck = 1;
        else
            usage();
    }
    if (optind == argc - 1)
        pong_user = argv[optind];
    else if (optind != argc)
        usage();

    // look up network address of pong server
    struct addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_NUMERICSERV;
    int r = getaddrinfo(pong_host, pong_port, &hints, &pong_addr);
    if (r != 0) {
        fprintf(stderr, "problem looking up %s: %s\n",
                pong_host, gai_strerror(r));
        exit(1);
    }

    // reset pong board and get its dimensions
    int width, height;
    {
        http_connection* conn = http_connect(pong_addr);
        http_send_request(conn, nocheck ? "reset?nocheck=1" : "reset");
        http_receive_response_headers(conn);
        http_receive_response_body(conn);
        if (conn->status_code != 200
            || sscanf(conn->buf, "%d %d\n", &width, &height) != 2
            || width <= 0 || height <= 0) {
            fprintf(stderr, "bad response to \"reset\" RPC: %d %s\n",
                    conn->status_code, http_truncate_response(conn));
            exit(1);
        }
        http_close(conn);
    }
    // measure future times relative to this moment
    elapsed_base = timestamp();

    // print display URL
    printf("Display: http://%s:%s/%s/%s\n",
           pong_host, pong_port, pong_user,
           nocheck ? " (NOCHECK mode)" : "");

    // initialize global synchronization objects
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&condvar, NULL);

    // play game
    int x = 0, y = 0, dx = 1, dy = 1;
    while (1) {
        // create a new thread to handle the next position
        pong_args pa;
        pa.x = x;
        pa.y = y;
        pthread_t pt;
        r = pthread_create(&pt, NULL, pong_thread, &pa);
        if (r != 0) {
            fprintf(stderr, "%.3f sec: pthread_create: %s\n",
                    elapsed(), strerror(r));
            exit(1);
        }

        // wait until that thread signals us to continue
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&condvar, &mutex);
        pthread_mutex_unlock(&mutex);

        // update position
        x += dx;
        y += dy;
        if (x < 0 || x >= width) {
            dx = -dx;
            x += 2 * dx;
        }
        if (y < 0 || y >= height) {
            dy = -dy;
            y += 2 * dy;
        }

        // wait 0.1sec
        usleep(100000);
    }
}
예제 #3
0
// pong_thread(threadarg)
//    Connect to the server at the position indicated by `threadarg`
//    (which is a pointer to a `pong_args` structure).
void* pong_thread(void* threadarg) {
    pthread_detach(pthread_self());

    // Copy thread arguments onto our stack.
    pong_args pa = *((pong_args*) threadarg);

    char url[256];
    snprintf(url, sizeof(url), "move?x=%d&y=%d&style=on",
             pa.x, pa.y);
    http_connection* conn;
    size_t sleeptime = 10000;
retry:
    // find reusable connection using LIFO access
	pthread_mutex_lock(&table_lock);
	if(conn_done_num > 0) {
		conn = conn_done_table[conn_done_num - 1];
		--conn_done_num;
		pthread_mutex_unlock(&table_lock);
	} else {
		// if not, create a new connection
		pthread_mutex_unlock(&table_lock);
    	conn = http_connect(pong_addr);
    }
    // let other threads wait for a sleeping thread due to server down
    pthread_mutex_lock(&time_lock);
    while(stop_time != 0) {
    	 pthread_cond_wait(&stop_time_cond, &time_lock);
    }
    pthread_mutex_unlock(&time_lock);
    // send request after the server has waken up
    http_send_request(conn, url);
    http_receive_response_headers(conn);
    // failed connection
	while(conn->state == HTTP_BROKEN && conn->status_code == -1) {
		http_close(conn);
		// usleep less than 1 second
	    if(sleeptime < 1000000)
	    	usleep(sleeptime);
		else {
	   		// sleep longer than a second
	    	sleep(1);
	    	usleep(sleeptime % 1000000);
	    }
	    // keep sleep time less than 2 seconds and double each retry
		if(sleeptime <= 1000000)
	    	sleeptime += sleeptime;
    	goto retry;
	}
	
    if (conn->status_code != 200)
        fprintf(stderr, "%.3f sec: warning: %d,%d: "
                "server returned status %d (expected 200)\n",
                elapsed(), pa.x, pa.y, conn->status_code);
    // signal more thread creation after having received header
	pthread_cond_signal(&condvar);
    http_receive_response_body(conn);
    // if server sends STOP, read the time in millisecond to stop_time
    pthread_mutex_lock(&time_lock);
    if(stop_time == 0 && sscanf(http_truncate_response(conn), "+%d STOP", &stop_time) && stop_time != 0) {
    	pthread_mutex_unlock(&time_lock);
    	// sleep less than 1 second
    	if(stop_time < 1000)
			usleep(stop_time * 1000);
		else {
			// sleep longer than 1 second
			sleep(stop_time / 1000);
			usleep((stop_time % 1000) * 1000);
		}
    	pthread_mutex_lock(&time_lock);
		stop_time = 0;
		// woke up, tell all threads to continue
		pthread_cond_broadcast(&stop_time_cond);
    	pthread_mutex_unlock(&time_lock);
    } else if (stop_time != 0) {
    	while(stop_time != 0) {
    		pthread_cond_wait(&stop_time_cond, &time_lock);
    	}
    	if(sscanf(http_truncate_response(conn), "+%d STOP", &stop_time) && stop_time != 0) {
    		pthread_mutex_unlock(&time_lock);
    		if(stop_time < 1000)
				usleep(stop_time * 1000);
			else {
				sleep(stop_time / 1000);
				usleep((stop_time % 1000) * 1000);
			}
    		pthread_mutex_lock(&time_lock);
			stop_time = 0;
			pthread_cond_broadcast(&stop_time_cond);
    		pthread_mutex_unlock(&time_lock);
    	} else {
    		pthread_mutex_unlock(&time_lock);
    	}
    } else {
    	pthread_mutex_unlock(&time_lock);
    }
    double result = strtod(conn->buf, NULL);
    if (result < 0) {
        fprintf(stderr, "%.3f sec: server returned error: %s\n",
                elapsed(), http_truncate_response(conn));
        exit(1);
    }
	// if the connection has status done, keep it in the connection table
	pthread_mutex_lock(&table_lock);
    if(conn->state == HTTP_DONE && conn_done_num < 29) {
    	conn_done_table[conn_done_num] = conn;
    	++conn_done_num;
		pthread_mutex_unlock(&table_lock);
    } else {
		pthread_mutex_unlock(&table_lock);
    	http_close(conn);
    }

    // signal the main thread to continue
    // pthread_cond_signal(&condvar);
    // and exit!
    pthread_exit(NULL);
}