thread_safe_page *original_io_request::complete_req(thread_safe_page *p, bool lock) { if (get_req_type() == io_request::BASIC_REQ) { int page_off; thread_safe_page *ret = NULL; char *req_buf; int req_size; if (within_1page()) { page_off = get_offset() - ROUND_PAGE(get_offset()); req_buf = get_buf(); req_size = get_size(); } else { io_request extracted; extract(p->get_offset(), PAGE_SIZE, extracted); page_off = extracted.get_offset() - ROUND_PAGE(extracted.get_offset()); req_buf = extracted.get_buf(); req_size = extracted.get_size(); } if (lock) p->lock(); if (get_access_method() == WRITE) { memcpy((char *) p->get_data() + page_off, req_buf, req_size); if (!p->set_dirty(true)) ret = p; } else /* I assume the data I read never crosses the page boundary */ memcpy(req_buf, (char *) p->get_data() + page_off, req_size); if (lock) p->unlock(); return ret; } else { p->inc_ref(); get_page_status(p).pg = p; return NULL; } }
static int give_write_copy (int requester_id, int request_id, int page_number) { int result; printf("%d: pre-lock\n", thisid); pthread_mutex_lock(&locks[page_number]); printf("%d: post-lock\n", thisid); int owner_id = get_owner(page_number); if (owner_id != thisid) { printf("%d: wtf\n", thisid); pthread_mutex_unlock(&locks[page_number]); return -E_INCORRECT_OWNER; } struct PageStatus *page_status = get_page_status(page_number); printf("%d: page_status->status: %d\n", thisid, page_status->status); switch (page_status->status) { case READABLE: { int i; int had_read_only; for (i = 0; i < nowners; i++) { if (i == requester_id) { had_read_only = (page_status->status_by_owner[i] == READING); continue; } if (i == thisid) { if (page_status->status_by_owner[i] == READING) { // Set local page to PROT_NONE at end of function continue; } else { // This shouldn't happen - the local copy should become // readable as soon the page status becomes READABLE result = -E_INCONSISTENT_STATE; break; } } if (page_status->status_by_owner[i] == READING) { // Tell i that it is INVALIDATED printf("%d: Telling %d that it is INVALIDATED\n", thisid, i); struct Message m = create_message(SET_PERMISSION, INVALIDATED, page_number); printf("%d: sending message of type %c\n", thisid, m.msg_type); result = send_to(i, &m); if (result < 0) break; page_status->status_by_owner[i] = INVALIDATED; } } page_status->status_by_owner[requester_id] = MODIFYING; page_status->modifying_owner = requester_id; page_status->status = MODIFIED; if (requester_id == thisid) { // Set local page to PROT_READ_WRITE printf("%d: Setting local page %d to PROT_READ_WRITE\n", thisid, page_number); result = set_permissions((void *) get_pageaddr(page_number), PGSIZE, PROT_READ_WRITE); if (result < 0) break; } else { if (had_read_only) { // Tell requester_id that it has PROT_READ_WRITE access struct Message m = create_message(SET_PERMISSION, MODIFYING, page_number); m.is_response = 1; if (request_id == NO_RESPONSE) { result = E_INCONSISTENT_STATE; break; } m.index = request_id; result = send_to(requester_id, &m); if (result < 0) break; } else { // Transfer page over network to requester_id and tell it // it has PROT_READ_WRITE access struct Message m = create_message(SEND_PAGE, MODIFYING, page_number); memcpy((void *) m.page, (void *) get_pageaddr(page_number), PGSIZE); m.is_response = 1; if (request_id == NO_RESPONSE) { result = E_INCONSISTENT_STATE; break; } m.index = request_id; result = send_to(requester_id, &m); if (result < 0) break; } } // Set local page to PROT_NONE result = set_permissions((void *) get_pageaddr(page_number), PGSIZE, PROT_NONE); if (result < 0) break; page_status->status_by_owner[thisid] = INVALIDATED; result = 0; break; } case MODIFIED: { int modifier = page_status->modifying_owner; if (modifier == requester_id) { // The modifier should have read-write permissions, in which // case a page not fault should not be thrown and this // should never be called. result = -E_INCONSISTENT_STATE; break; } if (modifier == thisid) { // Set local page to PROT_NONE at end of method } else { // Tell modifier that it is INVALIDATED // Get modified page from modifier struct Message m = create_message(REQUEST_PAGE, INVALIDATED, page_number); // Upon receiving the message we should map the page locally result = send_and_wait_for_response(modifier, &m); if (result < 0) break; // Local page should already be set PROT_READ } page_status->status_by_owner[modifier] = INVALIDATED; page_status->status_by_owner[requester_id] = MODIFYING; page_status->modifying_owner = requester_id; if (requester_id == thisid) { // Set local page to PROT_READ_WRITE result = set_permissions((void *) get_pageaddr(page_number), PGSIZE, PROT_READ_WRITE); if (result < 0) break; } else { // Transfer page over network to requester_id and tell it it has // PROT_READ_WRITE access struct Message m = create_message(SEND_PAGE, MODIFYING, page_number); memcpy((void *) m.page, (void *) get_pageaddr(page_number), PGSIZE); m.is_response = 1; if (request_id == NO_RESPONSE) { result = E_INCONSISTENT_STATE; break; } m.index = request_id; result = send_to(requester_id, &m); if (result < 0) break; // Set local page to PROT_NONE result = set_permissions((void *) get_pageaddr(page_number), PGSIZE, PROT_NONE); if (result < 0) break; } result = 0; break; } default: { printf("Unhandled page status in give_write_copy.\n"); exit(-E_UNHANDLED_PAGE_STATUS); } } pthread_mutex_unlock(&locks[page_number]); return result; }
static int give_read_copy (int requester_id, int request_id, int page_number) { int result; pthread_mutex_lock(&locks[page_number]); int owner_id = get_owner(page_number); if (owner_id != thisid) { pthread_mutex_unlock(&locks[page_number]); return -E_INCORRECT_OWNER; } struct PageStatus *page_status = get_page_status(page_number); switch (page_status->status) { case READABLE: { if (requester_id == thisid) { // Status should not be readable without local copy having // read permissions; with these permissions, a page fault // should not be thrown and this should never be called result = -E_INCONSISTENT_STATE; break; } // Transfer page over network to owner_id and tell it it // has PROT_READ access struct Message m = create_message(SEND_PAGE, READING, page_number); memcpy((void *) m.page, (void *) get_pageaddr(page_number), PGSIZE); m.is_response = 1; if (request_id == NO_RESPONSE) { result = E_INCONSISTENT_STATE; break; } m.index = request_id; if ((result = send_to(owner_id, &m)) < 0) break; page_status->status_by_owner[requester_id] = READABLE; result = 0; break; } case MODIFIED: { int modifier = page_status->modifying_owner; if (modifier == requester_id) { // The modifier should have read-write permissions, in which // case a page not fault should not be thrown and this // should never be called. result = -E_INCONSISTENT_STATE; break; } if (modifier != thisid) { // Request page from modifier and tell it to set its // permissions to PROT_READ struct Message m = create_message(REQUEST_PAGE, READING, page_number); // Upon receiving the message we should map the page locally if ((result = send_and_wait_for_response(modifier, &m)) < 0) { break; } // Local page should already be set PROT_READ page_status->status_by_owner[thisid] = READING; } page_status->status_by_owner[modifier] = READING; page_status->modifying_owner = NO_OWNER; page_status->status = READABLE; if (requester_id != thisid) { // Transfer page over network to requester_id and tell it it // has PROT_READ access struct Message m = create_message(SEND_PAGE, READING, page_number); memcpy((void *) m.page, (void *) get_pageaddr(page_number), PGSIZE); m.is_response = 1; if (request_id == NO_RESPONSE) { result = E_INCONSISTENT_STATE; break; } m.index = request_id; result = send_to(requester_id, &m); if (result < 0) break; page_status->status_by_owner[requester_id] = READING; } result = 0; break; } default: printf("Unhandled page status in give_read_copy.\n"); exit(-E_UNHANDLED_PAGE_STATUS); } pthread_mutex_unlock(&locks[page_number]); return result; }