00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #define _GNU_SOURCE
00018 #include <sys/shm.h>
00019 #include <sys/sem.h>
00020 #include <sys/stat.h>
00021 #include <errno.h>
00022
00023 #include "common.h"
00024
00025 #ifdef _SEM_SEMUN_UNDEFINED
00026 union semun {
00027 int val;
00028 struct semid_ds *buf;
00029 unsigned short *array;
00030 struct seminfo *__buf;
00031 };
00032 #endif
00033
00034 int32_t
00035 init_shm (xmms_visualization_t *vis, int32_t id, int32_t shmid, xmms_error_t *err)
00036 {
00037 struct shmid_ds shm_desc;
00038 int32_t semid;
00039 void *buffer;
00040 int size;
00041 xmms_vis_client_t *c;
00042 xmmsc_vis_unixshm_t *t;
00043 union semun semopts;
00044
00045 x_fetch_client (id);
00046
00047
00048
00049
00050
00051
00052
00053
00054 buffer = shmat (shmid, NULL, 0);
00055 if (buffer == (void*)-1) {
00056 xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "couldn't attach to shared memory");
00057 x_release_client ();
00058 return -1;
00059 }
00060 shmctl (shmid, IPC_STAT, &shm_desc);
00061 size = shm_desc.shm_segsz / sizeof (xmmsc_vischunk_t);
00062
00063
00064 semid = semget (IPC_PRIVATE, 2, S_IRWXU + S_IRWXG + S_IRWXO);
00065 if (semid == -1) {
00066 xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "couldn't create semaphore set");
00067 x_release_client ();
00068 return -1;
00069 }
00070
00071
00072
00073 semopts.val = size;
00074 semctl (semid, 0, SETVAL, semopts);
00075 semopts.val = 0;
00076 semctl (semid, 1, SETVAL, semopts);
00077
00078
00079 c->type = VIS_UNIXSHM;
00080 t = &c->transport.shm;
00081 t->semid = semid;
00082 t->shmid = shmid;
00083 t->buffer = buffer;
00084 t->size = size;
00085 t->pos = 0;
00086
00087 x_release_client ();
00088
00089 xmms_log_info ("Visualization client %d initialised using Unix SHM", id);
00090 return semid;
00091 }
00092
00093 void cleanup_shm (xmmsc_vis_unixshm_t *t)
00094 {
00095 shmdt (t->buffer);
00096 semctl (t->semid, 0, IPC_RMID, 0);
00097 }
00098
00099
00100
00101
00102 static gboolean
00103 decrement_server (xmmsc_vis_unixshm_t *t)
00104 {
00105
00106 struct sembuf op = { 0, -1, IPC_NOWAIT };
00107
00108 while (semop (t->semid, &op, 1) == -1) {
00109 switch (errno) {
00110 case EINTR:
00111 break;
00112 case EAGAIN:
00113 return FALSE;
00114 default:
00115 perror ("Skipping visualization package");
00116 return FALSE;
00117 }
00118 }
00119 return TRUE;
00120 }
00121
00122
00123
00124
00125 static void
00126 increment_client (xmmsc_vis_unixshm_t *t)
00127 {
00128
00129 struct sembuf op = { 1, +1, 0 };
00130
00131 if (semop (t->semid, &op, 1) == -1) {
00132
00133 g_error ("visualization increment_client: %s\n", strerror (errno));
00134 }
00135 }
00136
00137 gboolean
00138 write_shm (xmmsc_vis_unixshm_t *t, xmms_vis_client_t *c, int32_t id, struct timeval *time, int channels, int size, short *buf)
00139 {
00140 xmmsc_vischunk_t *dest;
00141 short res;
00142
00143 if (!write_start_shm (id, t, &dest))
00144 return FALSE;
00145
00146 tv2net (dest->timestamp, time);
00147 dest->format = htons (c->format);
00148 res = fill_buffer (dest->data, &c->prop, channels, size, buf);
00149 dest->size = htons (res);
00150 write_finish_shm (id, t, dest);
00151
00152 return TRUE;
00153 }
00154
00155
00156 gboolean
00157 write_start_shm (int32_t id, xmmsc_vis_unixshm_t *t, xmmsc_vischunk_t **dest)
00158 {
00159 struct shmid_ds shm_desc;
00160
00161
00162 if (shmctl (t->shmid, IPC_STAT, &shm_desc) == -1) {
00163 g_error ("Checking SHM attachments failed: %s\n", strerror (errno));
00164 }
00165 if (shm_desc.shm_nattch == 1) {
00166 delete_client (id);
00167 return FALSE;
00168 }
00169 if (shm_desc.shm_nattch != 2) {
00170 g_error ("Unbelievable # of SHM attachments: %lu\n",
00171 (unsigned long) shm_desc.shm_nattch);
00172 }
00173
00174 if (!decrement_server (t)) {
00175 return FALSE;
00176 }
00177
00178 *dest = &t->buffer[t->pos];
00179 return TRUE;
00180 }
00181
00182 void
00183 write_finish_shm (int32_t id, xmmsc_vis_unixshm_t *t, xmmsc_vischunk_t *dest)
00184 {
00185 t->pos = (t->pos + 1) % t->size;
00186 increment_client (t);
00187 }