Download - Sysprog 13
- 1. C/C++ Linux System Programming
-
- Session 13
-
-
- User-space System Programming
-
- session 3
2. Outline
- Pipes & FIFOs
- SysV mechanisms
- POSIX mechanisms
3. IPC Mechanisms So Far
- Signals
- Exit status
- Fork Address space
4. Pipes
- Characteristics:
-
- Single reader single writer (uni-diriectional)
-
- File descriptors (unnamed)
-
- POSIX and Linux restrictions
-
- Pipefs
-
- SIGPIPE: No readers
-
- PAGE_SIZE max (blocking write!!)
- int pipe(int pipefd[2]);
- int dup2(int oldfd, int newfd);
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. FIFOs
- Characteristics
-
- Named pipes
-
- File system
- int mkfifo(const char *pathname, mode_t mode);
7. SysV Generic
- General Interface
-
- Get
-
-
- IPC_PRIVATE or key,
-
-
-
-
- key_t ftok(const char *pathname, int proj_id);
-
-
-
-
- Flags: IPC_CREAT / IPC_EXCL
-
-
- ctl
- Specific Ops & control details
- System-wide (named) or private
- Owner / Creator (time)
- Explicit removal
- ipc()
8. SysV Semaphores
- Resource: Array of Semaphore Primitives
- int semget(key_t key, int nsems, int semflg);
- Multiple critical regions
- Multiple instances of a resource
-
- Initialize to a value (# of available instances)
-
- -ve to get resource, +ve to release
-
- 0 means block (unless IPC_NOWAIT)
9. Semaphore control
- int semctl(int semid, int semnum, int cmd, ...); /* union semun */
-
- int val;/* SETVAL */
-
- struct semid_ds *buf;/* IPC_STAT, IPC_SET */
-
- unsigned short*array;/* GETALL, SETALL */
-
- struct seminfo*__buf;/* IPC_INFO (Linux) */
- Initialization: SETVAL / SETALL / IPC_SET
- Debugging: GETVAL / GETALL / INFO / STAT
- Removal: IPC_RMID
10. Semaphore Ops
- int semop(int semid, struct sembuf *sops, unsigned nsops);
- int semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout);
- struct sem_buf
-
- unsigned short sem_num;
-
- shortsem_op;
-
- shortsem_flg;/* SEM_UNDO, IPC_NOWAIT */
- Undoable operations
11. SysV Messages
- int msgget(key_t key, int msgflg);
- int msgctl(int msqid, int cmd, struct msqid_ds *buf);
- IPC_RMID, IPC_SET
- int msgsnd(int msqid, const voidmsgp, size_t msgsz, int msgflg);
-
- struct msgbuf {
-
- long mtype;/* > 0 */
-
- char mtext[1]; }
12. Msg Receival
- ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
- Msgtyp:
-
- 0 first
-
- > 0 (first of type) / MSG_EXCEPT
-
- < 0 (first less than |type|)
- Flags: MSG_NOERROR, IPC_NOWAIT, MSG_EXCEPT
13. SysV Shared Memory
- int shmget(key_t key, size_t size, int shmflg); /* SHM_HUGETLB, SHM_NORESERVE */
- int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- IPC_RMID: Mark for removal
- void *shmat(int shmid, const voidshmaddr, int shmflg); /*SHM_RDONLY SHM_REMAP */
- int shmdt(const void *shmaddr);
14. static void ipcsyslog_init(void) { if (DEBUG) printf("shmget(%x, %d,...) ", (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("shmget"); } G.shbuf = shmat(G.shmid, NULL, 0); if (G.shbuf == (void*) -1L) { /* shmat has bizarre error return */ bb_perror_msg_and_die("shmat"); } 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("semget"); } } 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("SMwdn"); } ... /* 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("SMwup"); } } 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. POSIX Generic
- Filesystem like
- Focus on the unified interface
-
- May be not as versatile (do you care?)
-
- Still some specifics
- Newer, e.g.
-
- mq_ in >= 2.6.6
-
- Shm_ in 2.4 was on mounted /dev/shm
16. POSIX Semaphores
- sem_t *sem_open(const char *name, int oflag);
- sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
- int sem_destroy(sem_t *sem);
- int sem_init(sem_t *sem, int pshared, unsigned int value);
17. Semaphore Ops
- int sem_wait(sem_t *sem);
- int sem_trywait(sem_t *sem);
- int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
- int sem_post(sem_t *sem);
- int sem_getvalue(sem_t *sem, int *sval);
18. POSIX Message Queues
- mqd_t mq_open(const char *name, int oflag);
- mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);
- ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);
- mqd_t mq_close(mqd_t mqdes);
- mqd_t mq_unlink(const char *name);
19. Mq Attributes
- mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
- mqd_t mq_getattr(mqd_t mqdes, struct mq_attr *attr);
- mqd_t mq_setattr(mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr);
-
- {long mq_flags; /* 0 or O_NONBLOCK */
-
- long mq_maxmsg;
-
- long mq_msgsize;
-
- long mq_curmsgs;};
20. POSIX Shared Memory
- int shm_open(const char *name, int oflag, mode_t mode);
- int shm_unlink(const char *name);
- From then on, mapping
21. Memory Mapping for Shared memory
- void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); /* MAP_SHARED */
- int munmap(void *start, size_t length);
- void *mremap(void *old_address, size_t old_size, size_t new_size, int flags);
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("munmap() failed: %s", pa_cstrerror(errno)); if (m->do_unlink) { char fn[32]; segment_name(fn, sizeof(fn), m->id); if (shm_unlink(fn) < 0) pa_log(" shm_unlink(%s) failed: %s", 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, "/pulse-shm-%u", id); return fn; } 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); }