XMMS2
|
00001 /* XMMS2 - X Music Multiplexer System 00002 * Copyright (C) 2003-2011 XMMS2 Team 00003 * 00004 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 */ 00016 00017 #include <sys/shm.h> 00018 #include <sys/sem.h> 00019 #include <sys/stat.h> 00020 #include <errno.h> 00021 00022 #include "common.h" 00023 00024 #ifdef _SEM_SEMUN_UNDEFINED 00025 union semun { 00026 int val; /* Value for SETVAL */ 00027 struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ 00028 unsigned short *array; /* Array for GETALL, SETALL */ 00029 struct seminfo *__buf; /* Buffer for IPC_INFO (Linux specific) */ 00030 }; 00031 #endif 00032 00033 int32_t 00034 init_shm (xmms_visualization_t *vis, int32_t id, int32_t shmid, xmms_error_t *err) 00035 { 00036 struct shmid_ds shm_desc; 00037 int32_t semid; 00038 void *buffer; 00039 int size; 00040 xmms_vis_client_t *c; 00041 xmmsc_vis_unixshm_t *t; 00042 union semun semopts; 00043 00044 x_fetch_client (id); 00045 00046 /* MR. DEBUG */ 00047 /* xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "lame, more lame, shm!"); 00048 x_release_client (); 00049 return -1; */ 00050 00051 00052 /* test the shm */ 00053 buffer = shmat (shmid, NULL, 0); 00054 if (buffer == (void*)-1) { 00055 xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "couldn't attach to shared memory"); 00056 x_release_client (); 00057 return -1; 00058 } 00059 shmctl (shmid, IPC_STAT, &shm_desc); 00060 size = shm_desc.shm_segsz / sizeof (xmmsc_vischunk_t); 00061 00062 /* setup the semaphore set */ 00063 semid = semget (IPC_PRIVATE, 2, S_IRWXU + S_IRWXG + S_IRWXO); 00064 if (semid == -1) { 00065 xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "couldn't create semaphore set"); 00066 x_release_client (); 00067 return -1; 00068 } 00069 00070 /* initially set semaphores - nothing to read, buffersize to write 00071 first semaphore is the server semaphore */ 00072 semopts.val = size; 00073 semctl (semid, 0, SETVAL, semopts); 00074 semopts.val = 0; 00075 semctl (semid, 1, SETVAL, semopts); 00076 00077 /* set up client structure */ 00078 c->type = VIS_UNIXSHM; 00079 t = &c->transport.shm; 00080 t->semid = semid; 00081 t->shmid = shmid; 00082 t->buffer = buffer; 00083 t->size = size; 00084 t->pos = 0; 00085 00086 x_release_client (); 00087 00088 xmms_log_info ("Visualization client %d initialised using Unix SHM", id); 00089 return semid; 00090 } 00091 00092 void cleanup_shm (xmmsc_vis_unixshm_t *t) 00093 { 00094 shmdt (t->buffer); 00095 semctl (t->semid, 0, IPC_RMID, 0); 00096 } 00097 00098 /** 00099 * Decrements the server's semaphor (to write the next chunk) 00100 */ 00101 static gboolean 00102 decrement_server (xmmsc_vis_unixshm_t *t) 00103 { 00104 /* alter semaphore 0 by -1, don't block */ 00105 struct sembuf op = { 0, -1, IPC_NOWAIT }; 00106 00107 while (semop (t->semid, &op, 1) == -1) { 00108 switch (errno) { 00109 case EINTR: 00110 break; 00111 case EAGAIN: 00112 return FALSE; 00113 default: 00114 perror ("Skipping visualization package"); 00115 return FALSE; 00116 } 00117 } 00118 return TRUE; 00119 } 00120 00121 /** 00122 * Increments the client's semaphor (after a chunk was written) 00123 */ 00124 static void 00125 increment_client (xmmsc_vis_unixshm_t *t) 00126 { 00127 /* alter semaphore 1 by 1, no flags */ 00128 struct sembuf op = { 1, +1, 0 }; 00129 00130 if (semop (t->semid, &op, 1) == -1) { 00131 /* there should not occur any error */ 00132 g_error ("visualization increment_client: %s\n", strerror (errno)); 00133 } 00134 } 00135 00136 gboolean 00137 write_shm (xmmsc_vis_unixshm_t *t, xmms_vis_client_t *c, int32_t id, struct timeval *time, int channels, int size, short *buf) 00138 { 00139 xmmsc_vischunk_t *dest; 00140 short res; 00141 00142 if (!write_start_shm (id, t, &dest)) 00143 return FALSE; 00144 00145 tv2net (dest->timestamp, time); 00146 dest->format = htons (c->format); 00147 res = fill_buffer (dest->data, &c->prop, channels, size, buf); 00148 dest->size = htons (res); 00149 write_finish_shm (id, t, dest); 00150 00151 return TRUE; 00152 } 00153 00154 00155 gboolean 00156 write_start_shm (int32_t id, xmmsc_vis_unixshm_t *t, xmmsc_vischunk_t **dest) 00157 { 00158 struct shmid_ds shm_desc; 00159 00160 /* first check if the client is still there */ 00161 if (shmctl (t->shmid, IPC_STAT, &shm_desc) == -1) { 00162 g_error ("Checking SHM attachments failed: %s\n", strerror (errno)); 00163 } 00164 if (shm_desc.shm_nattch == 1) { 00165 delete_client (id); 00166 return FALSE; 00167 } 00168 if (shm_desc.shm_nattch != 2) { 00169 g_error ("Unbelievable # of SHM attachments: %lu\n", 00170 (unsigned long) shm_desc.shm_nattch); 00171 } 00172 00173 if (!decrement_server (t)) { 00174 return FALSE; 00175 } 00176 00177 *dest = &t->buffer[t->pos]; 00178 return TRUE; 00179 } 00180 00181 void 00182 write_finish_shm (int32_t id, xmmsc_vis_unixshm_t *t, xmmsc_vischunk_t *dest) 00183 { 00184 t->pos = (t->pos + 1) % t->size; 00185 increment_client (t); 00186 }