230 likes | 338 Views
Project 1 Supplemental Lecture. Joe Mongeluzzi Jason Zhao Cornell CS 4411, September 14, 2012. Today’s Lecture. Administrative Information C Pointer Hints Project 1 FAQ Q&A/Discussion. Administrative Information. Project 1 due Sept. 21, 11:59 PM Submission via CMS
E N D
Project 1Supplemental Lecture Joe Mongeluzzi Jason Zhao Cornell CS 4411, September 14, 2012
Today’s Lecture • Administrative Information • C Pointer Hints • Project 1 FAQ • Q&A/Discussion
Administrative Information • Project 1 due Sept. 21, 11:59 PM • Submission via CMS • Submit single zip file • don’t create an extra folder to hold the content • submit only source files, in addition to README • don’t encrypt! • Instructions will be posted on website • Correctness and elegance are prized • Comment code, use proper indentation, remove excess debug (printf) statements
Pointer casting • A pointer has two components: • starting address of the data being pointed to • size of data type associated with this memory location int a = 66051;int *x = &a; x = 0x00001004*x = 0x00010203 pointer x: data starts from 0x00001004 and spans 4 bytes 0x00001000 0 0 0 0 3 2 1 0 0 0 0 0 0 0 0 0 0x00001004 endianness?
Pointer casting • Casting the pointer changes only the way the memory is interpreted. • It does not change the memory contents or the address stored in the pointer. int a = 66051;int *x = &a; char *y;y = (char*) x; x = 0x00001004*x = 0x00010203y = 0x00001004*y = 0x03 pointer y: data starts from 0x00001004 and spans 1 byte pointer x: data starts from 0x00001004 and spans 4 bytes 0x00001000 0 0 0 0 3 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0x00001004
Pointer casting • We can change the values from the casted pointer if we like. • No array bounds check in C! int a = 66501;int *x = &a;char *y = (char*) x; x = 0x00001004*x = 0x00010203y = 0x00001004*y = 0x04 y[2] = 0x01 0x00001000 0 0 0 0 3 0 2 0 0 1 0 0 0 0 0 0 0 0 0 0x00001004
Structures structbase {int first;int second;}; structderived {structbase original;int third;}; structbase* b;structderived* d; pointer b: data starts from 0x00001000 and spans 8 bytes (structis aligned) 0x00001000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 second first
Structures structbase {int first;int second;}; structderived {structbase original;int third;}; structbase* b;structderived* d; pointer d: data starts from 0x00001000 and spans 12 bytes (structis aligned) 0x00001000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 original third
Common questions on casting • Casting from a derived struct pointer to the base struct pointer is safe • any operation that works on data members of the base struct will not write outside of the space allocated for the derived struct structbase *b = (structbase*) d;b->first = 0xdaed; b->second = 0xfeeb; pointer d: data starts from 0x00001000 and spans 12 bytes (struct is aligned) d c a e a f d e b b a e b e e f 0 0 0 0 0 0 0 0 pointer b: data starts from 0x00001000 and spans 8 bytes.
Common questions on casting • What about casting from base struct to derived struct? • unless you are very sure you will not touch data fields other than those in the base struct • but if that is the case, why did you perform the cast? structderived *some_d= (structderived*) some_b; some_d->first = 1;some_d->second = 2; some_d->third = 3;
Common questions on casting • Writing outside of known bounds may cause unpredictable behavior • may overwrite another variable • may overwrite stack (and thus modify return address; a common exploit) • usually just crashes structderived *some_d= (structderived*) some_b; some_d->first = 1;some_d->second = 2; some_d->third = 3;
void* pointers • Review: a pointer has two components • starting address of the data being pointed to • size of data type associated with this memory location • void* pointers are not associated with any data type • has only a starting address • no known size, therefore not possible to tell where data ends in memory • malloc() is a good example
Casting void* pointers • casting to void* from other pointer types • automatic, no need to prepend (void*) • other pointers can easily cast to void*; just ignore the size of the data type • casting to other pointer types from void* • explicit cast required • destination data type supplies the size of the data type
Queue • All* queue operations take in an existing queue. • intqueue_append(queue_t, void *item); • Append takes a pointer to an existing object, it is your job to link that pointer/object to the rest of your queue • intqueue_deque(queue_t queue, void **item); • Dequeue removes the first item from the queue and returns it to the caller via the variable “item” • intqueue_delete(queue_t queue, void **item); • Delete takes a pointer to the exact element that you appended and removes it from the queue *all queue functions except queue_new()
Queue Abstraction Head Ptr3 Ptr1 Ptr2 Ptr4 Obj3 Obj1 Obj2 Obj4 myPtr dPtr Queue_dequeue(myQ, myPtr) Queue_delete(myQ, dPtr)
Queue • intqueue_iterate(queue_t, PFAny, void *); • Iterate applies a functions f to all elements of the queue. Corner cases, if any application of the function f fails (i.e., returns a -1), immediately terminate the iteration and return -1. • intqueue_free(queue_t); • Free returns all memory allocated to the queue structure back to the OS. Free does not free the memory of the actual objects stored in the queue.
Queue • General *Pointers: • Return correct error codes in all cases – unlike Java, C does not have exceptions therefore you must ensure your queue returns the correct error code when something goes wrong. • Check your code for memory leaks – Visual Studio provides tools for detecting memory leaks but you should still reason about your code!
Minithread • Minithreads are the fundamental building block of your OS • You must implement the entire infrastructure to support minithreads including but not limited to: • Thread creation • Thread state (TCB) • Context switching • Thread blocking • Thread cleanup/deletion • As an OS, you must NEVER terminate. This is achieved using an idle thread. • What should the idle thread do?
Typical PortOS Execution Thread Creation System Initialize Thread Execution Ready Idle Thread Waiting Running Thread Deletion Thread Termination
Semaphore • Low level synchronization primitive • What is the purpose of a semaphore? • Mutual exclusion • Eliminates busy waiting • Common operations • semaphore_P – “procures” the semaphore • P is a potentially blocking operation • semaphore_V – “vacates” the semaphore • V should never block
Semaphore Internals • What should a semaphore store? • Count • List of threads • TAS lock • Has internal state! However the internal state of a semaphore should NEVER be made visible to observers. • Uses TAS locks, however you should omit the locking in project 1. • Be sure to initialize the semaphore before you use it.
Application • Last part of the project is a simple application that demonstrates your system components • Free to make this from scratch, but must follow description in assignment • Should use semaphores, no busy spinning! • Test with different values for N (employees) and M (customers)
Questions Questions?