XMMS2
unixshm.c
Go to the documentation of this file.
1 /* XMMS2 - X Music Multiplexer System
2  * Copyright (C) 2003-2011 XMMS2 Team
3  *
4  * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  */
16 
17 #define _GNU_SOURCE
18 #include <sys/shm.h>
19 #include <sys/sem.h>
20 #include <sys/stat.h>
21 #include <errno.h>
22 
23 #include "common.h"
24 
25 #ifdef _SEM_SEMUN_UNDEFINED
26  union semun {
27  int val; /* Value for SETVAL */
28  struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
29  unsigned short *array; /* Array for GETALL, SETALL */
30  struct seminfo *__buf; /* Buffer for IPC_INFO (Linux specific) */
31  };
32 #endif
33 
34 int32_t
35 init_shm (xmms_visualization_t *vis, int32_t id, int32_t shmid, xmms_error_t *err)
36 {
37  struct shmid_ds shm_desc;
38  int32_t semid;
39  void *buffer;
40  int size;
43  union semun semopts;
44 
45  x_fetch_client (id);
46 
47  /* MR. DEBUG */
48  /* xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "lame, more lame, shm!");
49  x_release_client ();
50  return -1; */
51 
52 
53  /* test the shm */
54  buffer = shmat (shmid, NULL, 0);
55  if (buffer == (void*)-1) {
56  xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "couldn't attach to shared memory");
58  return -1;
59  }
60  shmctl (shmid, IPC_STAT, &shm_desc);
61  size = shm_desc.shm_segsz / sizeof (xmmsc_vischunk_t);
62 
63  /* setup the semaphore set */
64  semid = semget (IPC_PRIVATE, 2, S_IRWXU + S_IRWXG + S_IRWXO);
65  if (semid == -1) {
66  xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "couldn't create semaphore set");
68  return -1;
69  }
70 
71  /* initially set semaphores - nothing to read, buffersize to write
72  first semaphore is the server semaphore */
73  semopts.val = size;
74  semctl (semid, 0, SETVAL, semopts);
75  semopts.val = 0;
76  semctl (semid, 1, SETVAL, semopts);
77 
78  /* set up client structure */
79  c->type = VIS_UNIXSHM;
80  t = &c->transport.shm;
81  t->semid = semid;
82  t->shmid = shmid;
83  t->buffer = buffer;
84  t->size = size;
85  t->pos = 0;
86 
88 
89  xmms_log_info ("Visualization client %d initialised using Unix SHM", id);
90  return semid;
91 }
92 
94 {
95  shmdt (t->buffer);
96  semctl (t->semid, 0, IPC_RMID, 0);
97 }
98 
99 /**
100  * Decrements the server's semaphor (to write the next chunk)
101  */
102 static gboolean
103 decrement_server (xmmsc_vis_unixshm_t *t)
104 {
105  /* alter semaphore 0 by -1, don't block */
106  struct sembuf op = { 0, -1, IPC_NOWAIT };
107 
108  while (semop (t->semid, &op, 1) == -1) {
109  switch (errno) {
110  case EINTR:
111  break;
112  case EAGAIN:
113  return FALSE;
114  default:
115  perror ("Skipping visualization package");
116  return FALSE;
117  }
118  }
119  return TRUE;
120 }
121 
122 /**
123  * Increments the client's semaphor (after a chunk was written)
124  */
125 static void
126 increment_client (xmmsc_vis_unixshm_t *t)
127 {
128  /* alter semaphore 1 by 1, no flags */
129  struct sembuf op = { 1, +1, 0 };
130 
131  if (semop (t->semid, &op, 1) == -1) {
132  /* there should not occur any error */
133  g_error ("visualization increment_client: %s\n", strerror (errno));
134  }
135 }
136 
137 gboolean
138 write_shm (xmmsc_vis_unixshm_t *t, xmms_vis_client_t *c, int32_t id, struct timeval *time, int channels, int size, short *buf)
139 {
140  xmmsc_vischunk_t *dest;
141  short res;
142 
143  if (!write_start_shm (id, t, &dest))
144  return FALSE;
145 
146  tv2net (dest->timestamp, time);
147  dest->format = htons (c->format);
148  res = fill_buffer (dest->data, &c->prop, channels, size, buf);
149  dest->size = htons (res);
150  write_finish_shm (id, t, dest);
151 
152  return TRUE;
153 }
154 
155 
156 gboolean
158 {
159  struct shmid_ds shm_desc;
160 
161  /* first check if the client is still there */
162  if (shmctl (t->shmid, IPC_STAT, &shm_desc) == -1) {
163  g_error ("Checking SHM attachments failed: %s\n", strerror (errno));
164  }
165  if (shm_desc.shm_nattch == 1) {
166  delete_client (id);
167  return FALSE;
168  }
169  if (shm_desc.shm_nattch != 2) {
170  g_error ("Unbelievable # of SHM attachments: %lu\n",
171  (unsigned long) shm_desc.shm_nattch);
172  }
173 
174  if (!decrement_server (t)) {
175  return FALSE;
176  }
177 
178  *dest = &t->buffer[t->pos];
179  return TRUE;
180 }
181 
182 void
184 {
185  t->pos = (t->pos + 1) % t->size;
186  increment_client (t);
187 }
xmmsc_vischunk_t * buffer
xmmsc_vis_properties_t prop
Definition: common.h:37
The structures for a vis client.
Definition: common.h:30
union xmms_vis_client_t::@2 transport
short fill_buffer(int16_t *dest, xmmsc_vis_properties_t *prop, int channels, int size, short *src)
Definition: format.c:149
#define x_fetch_client(id)
Definition: common.h:63
xmmsc_vis_transport_t type
Definition: common.h:35
#define x_release_client()
Definition: common.h:71
#define xmms_log_info(fmt,...)
Definition: xmms_log.h:34
void write_finish_shm(int32_t id, xmmsc_vis_unixshm_t *t, xmmsc_vischunk_t *dest)
Definition: unixshm.c:183
void cleanup_shm(xmmsc_vis_unixshm_t *t)
Definition: unixshm.c:93
data describing a unixshm transport
void delete_client(int32_t id)
Definition: object.c:84
Package format for vis data, encapsulated by unixshm or udp transport.
G_BEGIN_DECLS struct xmms_error_St xmms_error_t
xmmsc_vis_unixshm_t shm
Definition: common.h:32
int16_t data[2 *XMMSC_VISUALIZATION_WINDOW_SIZE]
void tv2net(int32_t *d, struct timeval *t)
Definition: timestamp.c:29
gboolean write_start_shm(int32_t id, xmmsc_vis_unixshm_t *t, xmmsc_vischunk_t **dest)
Definition: unixshm.c:157
unsigned short format
Definition: common.h:36
The structures for the vis module.
Definition: common.h:78
gboolean write_shm(xmmsc_vis_unixshm_t *t, xmms_vis_client_t *c, int32_t id, struct timeval *time, int channels, int size, short *buf)
Definition: unixshm.c:138
int32_t init_shm(xmms_visualization_t *vis, int32_t id, int32_t shmid, xmms_error_t *err)
Definition: unixshm.c:35