XMMS2
unixshm.c
Go to the documentation of this file.
1 /* XMMS2 - X Music Multiplexer System
2  * Copyright (C) 2003-2009 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 #define _GNU_SOURCE
17 #include <sys/shm.h>
18 #include <sys/sem.h>
19 #include <sys/stat.h>
20 #include <errno.h>
21 
22 #include "common.h"
23 
24 #ifdef _SEM_SEMUN_UNDEFINED
25  union semun {
26  int val; /* Value for SETVAL */
27  struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
28  unsigned short *array; /* Array for GETALL, SETALL */
29  struct seminfo *__buf; /* Buffer for IPC_INFO (Linux specific) */
30  };
31 #endif
32 
33 int32_t
34 init_shm (xmms_visualization_t *vis, int32_t id, int32_t shmid, xmms_error_t *err)
35 {
36  struct shmid_ds shm_desc;
37  int32_t semid;
38  void *buffer;
39  int size;
42  union semun semopts;
43 
44  x_fetch_client (id);
45 
46  /* MR. DEBUG */
47  /* xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "lame, more lame, shm!");
48  x_release_client ();
49  return -1; */
50 
51 
52  /* test the shm */
53  buffer = shmat (shmid, NULL, 0);
54  if (buffer == (void*)-1) {
55  xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "couldn't attach to shared memory");
57  return -1;
58  }
59  shmctl (shmid, IPC_STAT, &shm_desc);
60  size = shm_desc.shm_segsz / sizeof (xmmsc_vischunk_t);
61 
62  /* setup the semaphore set */
63  semid = semget (IPC_PRIVATE, 2, S_IRWXU + S_IRWXG + S_IRWXO);
64  if (semid == -1) {
65  xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "couldn't create semaphore set");
67  return -1;
68  }
69 
70  /* initially set semaphores - nothing to read, buffersize to write
71  first semaphore is the server semaphore */
72  semopts.val = size;
73  semctl (semid, 0, SETVAL, semopts);
74  semopts.val = 0;
75  semctl (semid, 1, SETVAL, semopts);
76 
77  /* set up client structure */
78  c->type = VIS_UNIXSHM;
79  t = &c->transport.shm;
80  t->semid = semid;
81  t->shmid = shmid;
82  t->buffer = buffer;
83  t->size = size;
84  t->pos = 0;
85 
87 
88  xmms_log_info ("Visualization client %d initialised using Unix SHM", id);
89  return semid;
90 }
91 
93 {
94  shmdt (t->buffer);
95  semctl (t->semid, 0, IPC_RMID, 0);
96 }
97 
98 /**
99  * Decrements the server's semaphor (to write the next chunk)
100  */
101 static gboolean
102 decrement_server (xmmsc_vis_unixshm_t *t)
103 {
104  /* alter semaphore 0 by -1, don't block */
105  struct sembuf op = { 0, -1, IPC_NOWAIT };
106 
107  while (semop (t->semid, &op, 1) == -1) {
108  switch (errno) {
109  case EINTR:
110  break;
111  case EAGAIN:
112  return FALSE;
113  default:
114  perror ("Skipping visualization package");
115  return FALSE;
116  }
117  }
118  return TRUE;
119 }
120 
121 /**
122  * Increments the client's semaphor (after a chunk was written)
123  */
124 static void
125 increment_client (xmmsc_vis_unixshm_t *t)
126 {
127  /* alter semaphore 1 by 1, no flags */
128  struct sembuf op = { 1, +1, 0 };
129 
130  if (semop (t->semid, &op, 1) == -1) {
131  /* there should not occur any error */
132  g_error ("visualization increment_client: %s\n", strerror (errno));
133  }
134 }
135 
136 gboolean
137 write_shm (xmmsc_vis_unixshm_t *t, xmms_vis_client_t *c, int32_t id, struct timeval *time, int channels, int size, short *buf)
138 {
139  xmmsc_vischunk_t *dest;
140  short res;
141 
142  if (!write_start_shm (id, t, &dest))
143  return FALSE;
144 
145  tv2net (dest->timestamp, time);
146  dest->format = htons (c->format);
147  res = fill_buffer (dest->data, &c->prop, channels, size, buf);
148  dest->size = htons (res);
149  write_finish_shm (id, t, dest);
150 
151  return TRUE;
152 }
153 
154 
155 gboolean
157 {
158  struct shmid_ds shm_desc;
159 
160  /* first check if the client is still there */
161  if (shmctl (t->shmid, IPC_STAT, &shm_desc) == -1) {
162  g_error ("Checking SHM attachments failed: %s\n", strerror (errno));
163  }
164  if (shm_desc.shm_nattch == 1) {
165  delete_client (id);
166  return FALSE;
167  }
168  if (shm_desc.shm_nattch != 2) {
169  g_error ("Unbelievable # of SHM attachments: %lu\n",
170  (unsigned long) shm_desc.shm_nattch);
171  }
172 
173  if (!decrement_server (t)) {
174  return FALSE;
175  }
176 
177  *dest = &t->buffer[t->pos];
178  return TRUE;
179 }
180 
181 void
183 {
184  t->pos = (t->pos + 1) % t->size;
185  increment_client (t);
186 }
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:182
void cleanup_shm(xmmsc_vis_unixshm_t *t)
Definition: unixshm.c:92
data describing a unixshm transport
void delete_client(int32_t id)
Definition: object.c:91
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:156
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:137
int32_t init_shm(xmms_visualization_t *vis, int32_t id, int32_t shmid, xmms_error_t *err)
Definition: unixshm.c:34