Sysprog 13

1,419 views

Published on

session 13 of the system programming course made by eglug

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,419
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
33
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Sysprog 13

  1. 1. C/C++ Linux System Programming <ul><ul><li>Session 13 </li></ul></ul><ul><ul><li>User-space System Programming </li></ul></ul><ul><ul><li> – session 3 </li></ul></ul>
  2. 2. Outline <ul><li>Pipes & FIFOs </li></ul><ul><li>SysV mechanisms </li></ul><ul><li>POSIX mechanisms </li></ul>
  3. 3. IPC Mechanisms So Far <ul><li>Signals </li></ul><ul><li>Exit status </li></ul><ul><li>Fork Address space </li></ul>
  4. 4. Pipes <ul><li>Characteristics: </li></ul><ul><ul><li>Single reader – single writer (uni-diriectional) </li></ul></ul><ul><ul><li>File descriptors (unnamed) </li></ul></ul><ul><ul><li>POSIX and Linux restrictions </li></ul></ul><ul><ul><li>Pipefs </li></ul></ul><ul><ul><li>SIGPIPE: No readers </li></ul></ul><ul><ul><li>PAGE_SIZE max (blocking write!!) </li></ul></ul><ul><li>int pipe(int pipefd[2]); </li></ul><ul><li>int dup2(int oldfd, int newfd); </li></ul>
  5. 5. struct job *jp; struct nodelist *lp; int pipelen; int prevfd; int pip[2]; prevfd = -1; for (lp = n->npipe.cmdlist; lp; lp = lp->next) { ... pip[1] = -1; if (lp->next) { if (pipe(pip) < 0) { ... } } if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { ... if (pip[1] >= 0) { close(pip[0]); } if (prevfd > 0) { dup2(prevfd, 0); close(prevfd); } if (pip[1] > 1) { dup2(pip[1], 1); close(pip[1]); } /* Execute */ /* never returns */ } if (prevfd >= 0) close(prevfd); prevfd = pip[0]; close(pip[1]); }
  6. 6. FIFOs <ul><li>Characteristics </li></ul><ul><ul><li>Named pipes </li></ul></ul><ul><ul><li>File system </li></ul></ul><ul><li>int mkfifo(const char *pathname, mode_t mode); </li></ul>
  7. 7. SysV Generic <ul><li>General Interface </li></ul><ul><ul><li>Get </li></ul></ul><ul><ul><ul><li>IPC_PRIVATE or key, </li></ul></ul></ul><ul><ul><ul><ul><li>key_t ftok(const char *pathname, int proj_id); </li></ul></ul></ul></ul><ul><ul><ul><li>Flags: IPC_CREAT / IPC_EXCL </li></ul></ul></ul><ul><ul><li>ctl </li></ul></ul><ul><li>Specific Ops & control details </li></ul><ul><li>System-wide (named) or private </li></ul><ul><li>Owner / Creator (time) </li></ul><ul><li>Explicit removal </li></ul><ul><li>ipc() </li></ul>
  8. 8. SysV Semaphores <ul><li>Resource: Array of Semaphore Primitives </li></ul><ul><li>int semget(key_t key, int nsems, int semflg); </li></ul><ul><li>Multiple critical regions </li></ul><ul><li>Multiple instances of a resource </li></ul><ul><ul><li>Initialize to a value (# of available instances) </li></ul></ul><ul><ul><li>-ve to get resource, +ve to release </li></ul></ul><ul><ul><li>0 means block (unless IPC_NOWAIT) </li></ul></ul>
  9. 9. Semaphore control <ul><li>int semctl(int semid, int semnum, int cmd, ...); /* union semun */ </li></ul><ul><ul><li>int val; /* SETVAL */ </li></ul></ul><ul><ul><li>struct semid_ds *buf; /* IPC_STAT, IPC_SET */ </li></ul></ul><ul><ul><li>unsigned short *array; /* GETALL, SETALL */ </li></ul></ul><ul><ul><li>struct seminfo *__buf; /* IPC_INFO (Linux) */ </li></ul></ul><ul><li>Initialization: SETVAL / SETALL / IPC_SET </li></ul><ul><li>Debugging: GETVAL / GETALL / INFO / STAT </li></ul><ul><li>Removal: IPC_RMID </li></ul>
  10. 10. Semaphore Ops <ul><li>int semop(int semid, struct sembuf *sops, unsigned nsops); </li></ul><ul><li>int semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout); </li></ul><ul><li>struct sem_buf </li></ul><ul><ul><li>unsigned short sem_num; </li></ul></ul><ul><ul><li>short sem_op; </li></ul></ul><ul><ul><li>short sem_flg; /* SEM_UNDO, IPC_NOWAIT */ </li></ul></ul><ul><li>“Undoable” operations </li></ul>
  11. 11. SysV Messages <ul><li>int msgget(key_t key, int msgflg); </li></ul><ul><li>int msgctl(int msqid, int cmd, struct msqid_ds *buf); </li></ul><ul><li>IPC_RMID, IPC_SET </li></ul><ul><li>int msgsnd(int msqid, const void msgp, size_t msgsz, int msgflg); </li></ul><ul><ul><li>struct msgbuf { </li></ul></ul><ul><ul><li>long mtype; /* > 0 */ </li></ul></ul><ul><ul><li>char mtext[1]; } </li></ul></ul>
  12. 12. Msg Receival <ul><li>ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); </li></ul><ul><li>Msgtyp: </li></ul><ul><ul><li>0 first </li></ul></ul><ul><ul><li>> 0 (first of type) / MSG_EXCEPT </li></ul></ul><ul><ul><li>< 0 (first less than |type|) </li></ul></ul><ul><li>Flags: MSG_NOERROR, IPC_NOWAIT, MSG_EXCEPT </li></ul>
  13. 13. SysV Shared Memory <ul><li>int shmget(key_t key, size_t size, int shmflg); /* SHM_HUGETLB, SHM_NORESERVE */ </li></ul><ul><li>int shmctl(int shmid, int cmd, struct shmid_ds *buf); </li></ul><ul><li>IPC_RMID: Mark for removal </li></ul><ul><li>void *shmat(int shmid, const void shmaddr, int shmflg); /* SHM_RDONLY SHM_REMAP */ </li></ul><ul><li>int shmdt(const void *shmaddr); </li></ul>
  14. 14. static void ipcsyslog_init(void) { if (DEBUG) printf(&quot;shmget(%x, %d,...) &quot;, (int)KEY_ID, G.shm_size); G.shmid = shmget(KEY_ID, G.shm_size, IPC_CREAT | 0644); if (G.shmid == -1) { bb_perror_msg_and_die(&quot;shmget&quot;); } G.shbuf = shmat(G.shmid, NULL, 0); if (G.shbuf == (void*) -1L) { /* shmat has bizarre error return */ bb_perror_msg_and_die(&quot;shmat&quot;); } memset(G.shbuf, 0, G.shm_size); G.shbuf->size = G.shm_size - offsetof(struct shbuf_ds, data) - 1; /*G.shbuf->tail = 0;*/ // we'll trust the OS to set initial semval to 0 (let's hope) G.s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023); if (G.s_semid == -1) { if (errno == EEXIST) { G.s_semid = semget(KEY_ID, 2, 0); if (G.s_semid != -1) return; } bb_perror_msg_and_die(&quot;semget&quot;); } } static void log_to_shmem(const char *msg, int len) { int old_tail, new_tail; if (semop(G.s_semid, G.SMwdn, 3) == -1) { bb_perror_msg_and_die(&quot;SMwdn&quot;); } ... /* Circular buffer calculation */ memcpy(G.shbuf->data + old_tail, msg, k); if (semop(G.s_semid, G.SMwup, 1) == -1) { bb_perror_msg_and_die(&quot;SMwup&quot;); } } static void ipcsyslog_cleanup(void) { if (G.shmid != -1) { shmdt(G.shbuf); } if (G.shmid != -1) { shmctl(G.shmid, IPC_RMID, NULL); } if (G.s_semid != -1) { semctl(G.s_semid, 0, IPC_RMID, 0); } }
  15. 15. POSIX Generic <ul><li>Filesystem like </li></ul><ul><li>Focus on the unified interface </li></ul><ul><ul><li>May be not as versatile (do you care?) </li></ul></ul><ul><ul><li>Still some specifics </li></ul></ul><ul><li>Newer, e.g. </li></ul><ul><ul><li>mq_ in >= 2.6.6 </li></ul></ul><ul><ul><li>Shm_ in 2.4 was on mounted /dev/shm </li></ul></ul>
  16. 16. POSIX Semaphores <ul><li>sem_t *sem_open(const char *name, int oflag); </li></ul><ul><li>sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value); </li></ul><ul><li>int sem_destroy(sem_t *sem); </li></ul><ul><li>int sem_init(sem_t *sem, int pshared, unsigned int value); </li></ul>
  17. 17. Semaphore Ops <ul><li>int sem_wait(sem_t *sem); </li></ul><ul><li>int sem_trywait(sem_t *sem); </li></ul><ul><li>int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); </li></ul><ul><li>int sem_post(sem_t *sem); </li></ul><ul><li>int sem_getvalue(sem_t *sem, int *sval); </li></ul>
  18. 18. POSIX Message Queues <ul><li>mqd_t mq_open(const char *name, int oflag); </li></ul><ul><li>mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); </li></ul><ul><li>ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); </li></ul><ul><li>mqd_t mq_close(mqd_t mqdes); </li></ul><ul><li>mqd_t mq_unlink(const char *name); </li></ul>
  19. 19. Mq Attributes <ul><li>mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr); </li></ul><ul><li>mqd_t mq_getattr(mqd_t mqdes, struct mq_attr *attr); </li></ul><ul><li>mqd_t mq_setattr(mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr); </li></ul><ul><ul><li>{long mq_flags; /* 0 or O_NONBLOCK */ </li></ul></ul><ul><ul><li>long mq_maxmsg; </li></ul></ul><ul><ul><li>long mq_msgsize; </li></ul></ul><ul><ul><li>long mq_curmsgs; }; </li></ul></ul>
  20. 20. POSIX Shared Memory <ul><li>int shm_open(const char *name, int oflag, mode_t mode); </li></ul><ul><li>int shm_unlink(const char *name); </li></ul><ul><li>From then on, mapping </li></ul>
  21. 21. Memory Mapping for Shared memory <ul><li>void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); /* MAP_SHARED */ </li></ul><ul><li>int munmap(void *start, size_t length); </li></ul><ul><li>void *mremap(void *old_address, size_t old_size, size_t new_size, int flags); </li></ul>
  22. 22. POSIX shm example int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { char fn[32]; int fd = -1; struct shm_marker *marker; pa_random(&m->id, sizeof(m->id)); segment_name(fn, sizeof(fn), m->id); if ((fd = shm_open(fn, O_RDWR|O_CREAT|O_EXCL, mode & 0444)) < 0) { ... } m->size = size + PA_ALIGN(sizeof(struct shm_marker)); if (ftruncate(fd, m->size) < 0) { ... } if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { ... } marker = (struct shm_marker*) ((uint8_t*) m->ptr + m->size - PA_ALIGN(sizeof(struct shm_marker))); pa_atomic_store(&marker->pid, (int) getpid()); pa_atomic_store(&marker->marker, SHM_MARKER); ... m->do_unlink = 1; } void pa_shm_free(pa_shm *m) { ... if (munmap(m->ptr, m->size) < 0) pa_log(&quot;munmap() failed: %s&quot;, pa_cstrerror(errno)); if (m->do_unlink) { char fn[32]; segment_name(fn, sizeof(fn), m->id); if (shm_unlink(fn) < 0) pa_log(&quot; shm_unlink(%s) failed: %s&quot;, fn, pa_cstrerror(errno)); } ... memset(m, 0, sizeof(*m)); } struct shm_marker { pa_atomic_t marker; /* 0xbeefcafe */ pa_atomic_t pid; void *_reserverd1; void *_reserverd2; void *_reserverd3; void *_reserverd4; }; static char *segment_name(char *fn, size_t l, unsigned id) { pa_snprintf(fn, l, &quot;/pulse-shm-%u&quot;, id); return fn; }
  23. 23. struct pa_semaphore { sem_t sem; }; pa_semaphore* pa_semaphore_new(unsigned value) { pa_semaphore *s; s = pa_xnew(pa_semaphore, 1); &s->sem, 0, value); return s; } void pa_semaphore_free(pa_semaphore *s) { sem_destroy(&s->sem) ; } void pa_semaphore_post(pa_semaphore *s) { sem_post(&s->sem) ; } void pa_semaphore_wait(pa_semaphore *s) { int ret; do { ret = sem_wait(&s->sem); } while (ret < 0 && errno == EINTR); } pa_mempool* pa_mempool_new(int shared) { pa_mempool *p; ... p = pa_xnew(pa_mempool, 1); p->semaphore = pa_semaphore_new(0); p->block_size = PA_PAGE_ALIGN(PA_MEMPOOL_SLOT_SIZE); ... if (pa_shm_create_rw(&p->memory, p->n_blocks * p->block_size, shared, 0700) < 0) { } ... return p; } void pa_mempool_free(pa_mempool *p) { ... pa_shm_free(&p->memory); ... pa_semaphore_free(p->semaphore); pa_xfree(p); } static void memblock_wait(pa_memblock *b) { if (pa_atomic_load(&b->n_acquired) > 0) { pa_atomic_inc(&b->please_signal); while (pa_atomic_load(&b->n_acquired) > 0) pa_semaphore_wait(b->pool->semaphore); pa_atomic_dec(&b->please_signal); } } void pa_memblock_release(pa_memblock *b) { int r; r = pa_atomic_dec(&b->n_acquired); pa_assert(r >= 1); if (r == 1 && pa_atomic_load(&b->please_signal)) pa_semaphore_post(b->pool->semaphore); }

×