Sysprog 13

download Sysprog 13

If you can't read please download the document

description

session 13 of the system programming course made by eglug

Transcript of 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); }