aRts audio server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

gslcommon.c 39KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651
  1. /* GSL - Generic Sound Layer
  2. * Copyright (C) 2001 Tim Janik
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General
  15. * Public License along with this library; if not, write to the
  16. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. * Boston, MA 02110-1301, USA.
  18. */
  19. #include <unistd.h>
  20. #include <fcntl.h>
  21. #include <sys/utsname.h>
  22. #include <string.h>
  23. #include <sched.h>
  24. #include <errno.h>
  25. #include <sys/poll.h>
  26. #include <sys/stat.h>
  27. #include <sys/time.h>
  28. #include "gslcommon.h"
  29. #include "gsldatacache.h"
  30. /* some systems don't have ERESTART (which is what linux returns for system
  31. * calls on pipes which are being interrupted). most propably just use EINTR,
  32. * and maybe some can return both. so we check for both in the below code,
  33. * and alias ERESTART to EINTR if it's not present. compilers are supposed
  34. * to catch and optimize the doubled check arising from this.
  35. */
  36. #ifndef ERESTART
  37. #define ERESTART EINTR
  38. #endif
  39. #define PREALLOC (8)
  40. #define SIMPLE_CACHE_SIZE (64)
  41. #define TS8_SIZE (MAX (sizeof (GTrashStack), 8))
  42. #define DBG8_SIZE (MAX (sizeof (gsize), 8))
  43. /* --- variables --- */
  44. volatile guint64 gsl_externvar_tick_stamp = 0;
  45. static guint64 tick_stamp_system_time = 0;
  46. static guint global_tick_stamp_leaps = 0;
  47. static GslDebugFlags gsl_debug_flags = 0;
  48. /* --- memory allocation --- */
  49. static GslMutex global_memory = { 0, };
  50. static GTrashStack *simple_cache[SIMPLE_CACHE_SIZE] = { 0, 0, 0, /* ... */ };
  51. static gulong memory_allocated = 0;
  52. const guint
  53. gsl_alloc_upper_power2 (const gulong number)
  54. {
  55. return number ? 1 << g_bit_storage (number - 1) : 0;
  56. }
  57. static inline gpointer
  58. low_alloc (gsize mem_size)
  59. {
  60. gpointer mem;
  61. if (mem_size >= TS8_SIZE && mem_size / 8 < SIMPLE_CACHE_SIZE)
  62. {
  63. guint cell;
  64. mem_size = (mem_size + 7) & ~0x7;
  65. cell = (mem_size >> 3) - 1;
  66. GSL_SPIN_LOCK (&global_memory);
  67. mem = g_trash_stack_pop (simple_cache + cell);
  68. GSL_SPIN_UNLOCK (&global_memory);
  69. if (!mem)
  70. {
  71. guint8 *cache_mem = g_malloc (mem_size * PREALLOC);
  72. guint i;
  73. GSL_SPIN_LOCK (&global_memory);
  74. memory_allocated += mem_size * PREALLOC;
  75. for (i = 0; i < PREALLOC - 1; i++)
  76. {
  77. g_trash_stack_push (simple_cache + cell, cache_mem);
  78. cache_mem += mem_size;
  79. }
  80. GSL_SPIN_UNLOCK (&global_memory);
  81. mem = cache_mem;
  82. }
  83. }
  84. else
  85. {
  86. mem = g_malloc (mem_size);
  87. GSL_SPIN_LOCK (&global_memory);
  88. memory_allocated += mem_size;
  89. GSL_SPIN_UNLOCK (&global_memory);
  90. }
  91. return mem;
  92. }
  93. static inline void
  94. low_free (gsize mem_size,
  95. gpointer mem)
  96. {
  97. if (mem_size >= TS8_SIZE && mem_size / 8 < SIMPLE_CACHE_SIZE)
  98. {
  99. guint cell;
  100. mem_size = (mem_size + 7) & ~0x7;
  101. cell = (mem_size >> 3) - 1;
  102. GSL_SPIN_LOCK (&global_memory);
  103. g_trash_stack_push (simple_cache + cell, mem);
  104. GSL_SPIN_UNLOCK (&global_memory);
  105. }
  106. else
  107. {
  108. g_free (mem);
  109. GSL_SPIN_LOCK (&global_memory);
  110. memory_allocated -= mem_size;
  111. GSL_SPIN_UNLOCK (&global_memory);
  112. }
  113. }
  114. gpointer
  115. gsl_alloc_memblock (gsize block_size)
  116. {
  117. guint8 *cmem;
  118. gsize *debug_size;
  119. g_return_val_if_fail (block_size >= sizeof (gpointer), NULL); /* cache-link size */
  120. cmem = low_alloc (block_size + DBG8_SIZE);
  121. debug_size = (gsize*) cmem;
  122. *debug_size = block_size;
  123. cmem += DBG8_SIZE;
  124. return cmem;
  125. }
  126. void
  127. gsl_free_memblock (gsize block_size,
  128. gpointer mem)
  129. {
  130. gsize *debug_size;
  131. guint8 *cmem;
  132. g_return_if_fail (mem != NULL);
  133. cmem = mem;
  134. cmem -= DBG8_SIZE;
  135. debug_size = (gsize*) cmem;
  136. g_return_if_fail (block_size == *debug_size);
  137. low_free (block_size + DBG8_SIZE, cmem);
  138. }
  139. void
  140. gsl_alloc_report (void)
  141. {
  142. guint cell, cached = 0;
  143. GSL_SPIN_LOCK (&global_memory);
  144. for (cell = 0; cell < SIMPLE_CACHE_SIZE; cell++)
  145. {
  146. GTrashStack *trash = simple_cache[cell];
  147. guint memsize, n = 0;
  148. while (trash)
  149. {
  150. n++;
  151. trash = trash->next;
  152. }
  153. if (n)
  154. {
  155. memsize = (cell + 1) << 3;
  156. g_message ("cell %4u): %u bytes in %u nodes", memsize, memsize * n, n);
  157. cached += memsize * n;
  158. }
  159. }
  160. g_message ("%lu bytes allocated from system, %u bytes unused in cache", memory_allocated, cached);
  161. GSL_SPIN_UNLOCK (&global_memory);
  162. }
  163. gpointer
  164. gsl_alloc_memblock0 (gsize block_size)
  165. {
  166. gpointer mem = gsl_alloc_memblock (block_size);
  167. memset (mem, 0, block_size);
  168. return mem;
  169. }
  170. static void
  171. gsl_free_node_list (gpointer mem,
  172. gsize node_size)
  173. {
  174. struct { gpointer next, data; } *tmp, *node = mem;
  175. g_return_if_fail (node != NULL);
  176. g_return_if_fail (node_size >= 2 * sizeof (gpointer));
  177. /* FIXME: this can be optimized to an O(1) operation with T-style links in mem-caches */
  178. do
  179. {
  180. tmp = node->next;
  181. gsl_free_memblock (node_size, node);
  182. node = tmp;
  183. }
  184. while (node);
  185. }
  186. /* --- ring (circular-list) --- */
  187. static inline GslRing*
  188. gsl_ring_prepend_i (GslRing *head,
  189. gpointer data)
  190. {
  191. GslRing *ring = gsl_new_struct (GslRing, 1);
  192. ring->data = data;
  193. if (!head)
  194. {
  195. ring->prev = ring;
  196. ring->next = ring;
  197. }
  198. else
  199. {
  200. ring->prev = head->prev;
  201. ring->next = head;
  202. head->prev->next = ring;
  203. head->prev = ring;
  204. }
  205. return ring;
  206. }
  207. GslRing*
  208. gsl_ring_prepend (GslRing *head,
  209. gpointer data)
  210. {
  211. return gsl_ring_prepend_i (head, data);
  212. }
  213. GslRing*
  214. gsl_ring_prepend_uniq (GslRing *head,
  215. gpointer data)
  216. {
  217. GslRing *walk;
  218. for (walk = head; walk; walk = gsl_ring_walk (head, walk))
  219. if (walk->data == data)
  220. return head;
  221. return gsl_ring_prepend_i (head, data);
  222. }
  223. GslRing*
  224. gsl_ring_append (GslRing *head,
  225. gpointer data)
  226. {
  227. GslRing *ring;
  228. ring = gsl_ring_prepend_i (head, data);
  229. return head ? head : ring;
  230. }
  231. GslRing*
  232. gsl_ring_concat (GslRing *head1,
  233. GslRing *head2)
  234. {
  235. GslRing *tail1, *tail2;
  236. if (!head1)
  237. return head2;
  238. if (!head2)
  239. return head1;
  240. tail1 = head1->prev;
  241. tail2 = head2->prev;
  242. head1->prev = tail2;
  243. tail2->next = head1;
  244. head2->prev = tail1;
  245. tail1->next = head2;
  246. return head1;
  247. }
  248. GslRing*
  249. gsl_ring_remove_node (GslRing *head,
  250. GslRing *node)
  251. {
  252. if (!head)
  253. g_return_val_if_fail (head == NULL && node == NULL, NULL);
  254. if (!head || !node)
  255. return NULL;
  256. /* special case one item ring */
  257. if (head->prev == head)
  258. {
  259. g_return_val_if_fail (node == head, head);
  260. gsl_delete_struct (GslRing, node);
  261. return NULL;
  262. }
  263. g_return_val_if_fail (node != node->next, head); /* node can't be a one item ring here */
  264. node->next->prev = node->prev;
  265. node->prev->next = node->next;
  266. if (head == node)
  267. head = node->next;
  268. gsl_delete_struct (GslRing, node);
  269. return head;
  270. }
  271. GslRing*
  272. gsl_ring_remove (GslRing *head,
  273. gpointer data)
  274. {
  275. GslRing *walk;
  276. if (!head)
  277. return NULL;
  278. /* make tail data removal an O(1) operation */
  279. if (head->prev->data == data)
  280. return gsl_ring_remove_node (head, head->prev);
  281. for (walk = head; walk; walk = gsl_ring_walk (head, walk))
  282. if (walk->data == data)
  283. return gsl_ring_remove_node (head, walk);
  284. g_warning (G_STRLOC ": couldn't find data item (%p) to remove from ring (%p)", data, head);
  285. return head;
  286. }
  287. guint
  288. gsl_ring_length (GslRing *head)
  289. {
  290. GslRing *ring;
  291. guint i = 0;
  292. for (ring = head; ring; ring = gsl_ring_walk (head, ring))
  293. i++;
  294. return i;
  295. }
  296. GslRing*
  297. gsl_ring_find (GslRing *head,
  298. gconstpointer data)
  299. {
  300. GslRing *ring;
  301. for (ring = head; ring; ring = gsl_ring_walk (head, ring))
  302. if (ring->data == (gpointer) data)
  303. return ring;
  304. return NULL;
  305. }
  306. GslRing*
  307. gsl_ring_nth (GslRing *head,
  308. guint n)
  309. {
  310. GslRing *ring = head;
  311. while (n-- && ring)
  312. ring = gsl_ring_walk (head, ring);
  313. return ring;
  314. }
  315. gpointer
  316. gsl_ring_nth_data (GslRing *head,
  317. guint n)
  318. {
  319. GslRing *ring = head;
  320. while (n-- && ring)
  321. ring = gsl_ring_walk (head, ring);
  322. return ring ? ring->data : ring;
  323. }
  324. void
  325. gsl_ring_free (GslRing *head)
  326. {
  327. if (head)
  328. {
  329. head->prev->next = NULL;
  330. gsl_free_node_list (head, sizeof (*head));
  331. }
  332. }
  333. gpointer
  334. gsl_ring_pop_head (GslRing **head_p)
  335. {
  336. gpointer data;
  337. g_return_val_if_fail (head_p != NULL, NULL);
  338. if (!*head_p)
  339. return NULL;
  340. data = (*head_p)->data;
  341. *head_p = gsl_ring_remove_node (*head_p, *head_p);
  342. return data;
  343. }
  344. gpointer
  345. gsl_ring_pop_tail (GslRing **head_p)
  346. {
  347. gpointer data;
  348. g_return_val_if_fail (head_p != NULL, NULL);
  349. if (!*head_p)
  350. return NULL;
  351. data = (*head_p)->prev->data;
  352. *head_p = gsl_ring_remove_node (*head_p, (*head_p)->prev);
  353. return data;
  354. }
  355. GslRing*
  356. gsl_ring_insert_sorted (GslRing *head,
  357. gpointer data,
  358. GCompareFunc func)
  359. {
  360. gint cmp;
  361. g_return_val_if_fail (func != NULL, head);
  362. if (!head)
  363. return gsl_ring_prepend (head, data);
  364. /* typedef gint (*GCompareFunc) (gconstpointer a,
  365. * gconstpointer b);
  366. */
  367. cmp = func (data, head->data);
  368. if (cmp >= 0) /* insert after head */
  369. {
  370. GslRing *tmp, *tail = head->prev;
  371. /* make appending an O(1) operation */
  372. if (head == tail || func (data, tail->data) >= 0)
  373. return gsl_ring_append (head, data);
  374. /* walk forward while data >= tmp (skipping equal nodes) */
  375. for (tmp = head->next; tmp != tail; tmp = tmp->next)
  376. if (func (data, tmp->data) < 0)
  377. break;
  378. /* insert before sibling which is greater than data */
  379. gsl_ring_prepend (tmp, data); /* keep current head */
  380. return head;
  381. }
  382. else /* cmp < 0 */
  383. return gsl_ring_prepend (head, data);
  384. }
  385. /* --- GslThread --- */
  386. typedef struct
  387. {
  388. GslThreadFunc func;
  389. gpointer data;
  390. gint wpipe[2];
  391. volatile gint abort;
  392. guint64 awake_stamp;
  393. GslDebugFlags auxlog_reporter;
  394. const gchar *auxlog_section;
  395. } ThreadData;
  396. static GslMutex global_thread = { 0, };
  397. static GslRing *global_thread_list = NULL;
  398. static GslCond global_thread_cond = { 0, };
  399. static GslRing *awake_tdata_list = NULL;
  400. static ThreadData *main_thread_tdata = NULL;
  401. static GslThread *main_thread = NULL;
  402. static inline ThreadData*
  403. thread_data_from_gsl_thread (GslThread *thread)
  404. {
  405. GThread *gthread = (GThread*) thread;
  406. /* if gthread->data==NULL, we assume this is the main thread */
  407. return gthread->data ? gthread->data : main_thread_tdata;
  408. }
  409. static gpointer
  410. thread_wrapper (gpointer arg)
  411. {
  412. GslThread *self = gsl_thread_self ();
  413. ThreadData *tdata = arg;
  414. g_assert (tdata == thread_data_from_gsl_thread (gsl_thread_self ()));
  415. GSL_SYNC_LOCK (&global_thread);
  416. global_thread_list = gsl_ring_prepend (global_thread_list, self);
  417. gsl_cond_broadcast (&global_thread_cond);
  418. GSL_SYNC_UNLOCK (&global_thread);
  419. tdata->func (tdata->data);
  420. GSL_SYNC_LOCK (&global_thread);
  421. global_thread_list = gsl_ring_remove (global_thread_list, self);
  422. if (tdata->awake_stamp)
  423. awake_tdata_list = gsl_ring_remove (awake_tdata_list, tdata);
  424. gsl_cond_broadcast (&global_thread_cond);
  425. GSL_SYNC_UNLOCK (&global_thread);
  426. close (tdata->wpipe[0]);
  427. tdata->wpipe[0] = -1;
  428. close (tdata->wpipe[1]);
  429. tdata->wpipe[1] = -1;
  430. gsl_delete_struct (ThreadData, tdata);
  431. return NULL;
  432. }
  433. static ThreadData*
  434. create_tdata (void)
  435. {
  436. ThreadData *tdata;
  437. glong d_long;
  438. gint error;
  439. tdata = gsl_new_struct0 (ThreadData, 1);
  440. tdata->func = NULL;
  441. tdata->data = NULL;
  442. tdata->wpipe[0] = -1;
  443. tdata->wpipe[1] = -1;
  444. tdata->abort = FALSE;
  445. tdata->auxlog_reporter = 0;
  446. tdata->auxlog_section = NULL;
  447. error = pipe (tdata->wpipe);
  448. if (error == 0)
  449. {
  450. d_long = fcntl (tdata->wpipe[0], F_GETFL, 0);
  451. /* g_printerr ("pipe-readfd, blocking=%ld\n", d_long & O_NONBLOCK); */
  452. d_long |= O_NONBLOCK;
  453. error = fcntl (tdata->wpipe[0], F_SETFL, d_long);
  454. }
  455. if (error == 0)
  456. {
  457. d_long = fcntl (tdata->wpipe[1], F_GETFL, 0);
  458. /* g_printerr ("pipe-writefd, blocking=%ld\n", d_long & O_NONBLOCK); */
  459. d_long |= O_NONBLOCK;
  460. error = fcntl (tdata->wpipe[1], F_SETFL, d_long);
  461. }
  462. if (error)
  463. {
  464. close (tdata->wpipe[0]);
  465. close (tdata->wpipe[1]);
  466. gsl_delete_struct (ThreadData, tdata);
  467. tdata = NULL;
  468. }
  469. return tdata;
  470. }
  471. GslThread*
  472. gsl_thread_new (GslThreadFunc func,
  473. gpointer user_data)
  474. {
  475. gpointer gthread = NULL;
  476. ThreadData *tdata;
  477. GError *gerror = NULL;
  478. g_return_val_if_fail (func != NULL, FALSE);
  479. tdata = create_tdata ();
  480. if (tdata)
  481. {
  482. const gboolean joinable = FALSE;
  483. /* don't dare setting joinable to TRUE, that prevents the thread's
  484. * resources from being freed, since we don't offer pthread_join().
  485. * so we'd just rn out of stack at some point.
  486. */
  487. tdata->func = func;
  488. tdata->data = user_data;
  489. gthread = g_thread_create_full (thread_wrapper, tdata, 0, joinable, FALSE,
  490. G_THREAD_PRIORITY_NORMAL, &gerror);
  491. }
  492. if (gthread)
  493. {
  494. GSL_SYNC_LOCK (&global_thread);
  495. while (!gsl_ring_find (global_thread_list, gthread))
  496. gsl_cond_wait (&global_thread_cond, &global_thread);
  497. GSL_SYNC_UNLOCK (&global_thread);
  498. }
  499. else
  500. {
  501. if (tdata)
  502. {
  503. close (tdata->wpipe[0]);
  504. close (tdata->wpipe[1]);
  505. gsl_delete_struct (ThreadData, tdata);
  506. }
  507. g_warning ("Failed to create thread: %s", gerror->message);
  508. g_error_free (gerror);
  509. }
  510. return gthread;
  511. }
  512. GslThread*
  513. gsl_thread_self (void)
  514. {
  515. gpointer gthread = g_thread_self ();
  516. if (!gthread)
  517. g_error ("gsl_thread_self() failed");
  518. return gthread;
  519. }
  520. GslThread*
  521. gsl_thread_main (void)
  522. {
  523. return main_thread;
  524. }
  525. guint
  526. gsl_threads_get_count (void)
  527. {
  528. guint count;
  529. GSL_SYNC_LOCK (&global_thread);
  530. count = gsl_ring_length (global_thread_list);
  531. GSL_SYNC_UNLOCK (&global_thread);
  532. return count;
  533. }
  534. static void
  535. thread_wakeup_I (ThreadData *tdata)
  536. {
  537. guint8 data = 'W';
  538. gint r;
  539. do
  540. r = write (tdata->wpipe[1], &data, 1);
  541. while (r < 0 && (errno == EINTR || errno == ERESTART));
  542. }
  543. /**
  544. * gsl_thread_wakeup
  545. * @thread: thread to wake up
  546. * Wake up a currently sleeping thread. In practice, this
  547. * function simply causes the next call to gsl_thread_sleep()
  548. * within @thread to last for 0 seconds.
  549. */
  550. void
  551. gsl_thread_wakeup (GslThread *thread)
  552. {
  553. ThreadData *tdata;
  554. g_return_if_fail (thread != NULL);
  555. GSL_SYNC_LOCK (&global_thread);
  556. g_assert (gsl_ring_find (global_thread_list, thread));
  557. GSL_SYNC_UNLOCK (&global_thread);
  558. tdata = thread_data_from_gsl_thread (thread);
  559. thread_wakeup_I (tdata);
  560. }
  561. /**
  562. * gsl_thread_abort
  563. * @thread: thread to abort
  564. * Abort a currently running thread. This function does not
  565. * return until the thread in question terminated execution.
  566. * Note that the thread handle gets invalidated with invocation
  567. * of gsl_thread_abort() or gsl_thread_queue_abort().
  568. */
  569. void
  570. gsl_thread_abort (GslThread *thread)
  571. {
  572. ThreadData *tdata;
  573. g_return_if_fail (thread != NULL);
  574. g_return_if_fail (thread != main_thread);
  575. GSL_SYNC_LOCK (&global_thread);
  576. g_assert (gsl_ring_find (global_thread_list, thread));
  577. GSL_SYNC_UNLOCK (&global_thread);
  578. tdata = thread_data_from_gsl_thread (thread);
  579. GSL_SYNC_LOCK (&global_thread);
  580. tdata->abort = TRUE;
  581. thread_wakeup_I (tdata);
  582. while (gsl_ring_find (global_thread_list, thread))
  583. gsl_cond_wait (&global_thread_cond, &global_thread);
  584. GSL_SYNC_UNLOCK (&global_thread);
  585. }
  586. /**
  587. * gsl_thread_queue_abort
  588. * @thread: thread to abort
  589. * Same as gsl_thread_abort(), but returns as soon as possible,
  590. * even if thread hasn't stopped execution yet.
  591. * Note that the thread handle gets invalidated with invocation
  592. * of gsl_thread_abort() or gsl_thread_queue_abort().
  593. */
  594. void
  595. gsl_thread_queue_abort (GslThread *thread)
  596. {
  597. ThreadData *tdata;
  598. g_return_if_fail (thread != NULL);
  599. g_return_if_fail (thread != main_thread);
  600. GSL_SYNC_LOCK (&global_thread);
  601. g_assert (gsl_ring_find (global_thread_list, thread));
  602. GSL_SYNC_UNLOCK (&global_thread);
  603. tdata = thread_data_from_gsl_thread (thread);
  604. GSL_SYNC_LOCK (&global_thread);
  605. tdata->abort = TRUE;
  606. thread_wakeup_I (tdata);
  607. GSL_SYNC_UNLOCK (&global_thread);
  608. }
  609. /**
  610. * gsl_thread_aborted
  611. * @returns: %TRUE if the thread should abort execution
  612. * Find out if the currently running thread should be aborted (the thread is
  613. * supposed to return from its main thread function).
  614. */
  615. gboolean
  616. gsl_thread_aborted (void)
  617. {
  618. ThreadData *tdata = thread_data_from_gsl_thread (gsl_thread_self ());
  619. gboolean aborted;
  620. GSL_SYNC_LOCK (&global_thread);
  621. aborted = tdata->abort != FALSE;
  622. GSL_SYNC_UNLOCK (&global_thread);
  623. return aborted;
  624. }
  625. /**
  626. * gsl_thread_sleep
  627. * @max_msec: maximum amount of milli seconds to sleep (-1 for infinite time)
  628. * @returns: %TRUE if the thread should continue execution
  629. * Sleep for the amount of time given. This function may get interrupted
  630. * by wakeup or abort requests, it returns whether the thread is supposed
  631. * to continue execution after waking up. This function also processes
  632. * remaining data from the thread's poll fd.
  633. */
  634. gboolean
  635. gsl_thread_sleep (glong max_msec)
  636. {
  637. ThreadData *tdata = thread_data_from_gsl_thread (gsl_thread_self ());
  638. struct pollfd pfd;
  639. gint r, aborted;
  640. pfd.fd = tdata->wpipe[0];
  641. pfd.events = G_IO_IN;
  642. pfd.revents = 0;
  643. r = poll (&pfd, 1, max_msec);
  644. if (r < 0 && errno != EINTR)
  645. g_message (G_STRLOC ": poll() error: %s\n", g_strerror (errno));
  646. else if (pfd.revents & G_IO_IN)
  647. {
  648. guint8 data[64];
  649. do
  650. r = read (tdata->wpipe[0], data, sizeof (data));
  651. while ((r < 0 && (errno == EINTR || errno == ERESTART)) || r == sizeof (data));
  652. }
  653. GSL_SYNC_LOCK (&global_thread);
  654. aborted = tdata->abort != FALSE;
  655. GSL_SYNC_UNLOCK (&global_thread);
  656. return !aborted;
  657. }
  658. /**
  659. * gsl_thread_awake_after
  660. * RETURNS: GPollFD for the current thread
  661. * Get the GPollfd for the current thread which is used
  662. * to signal thread wakeups (e.g. due to
  663. * gsl_thread_abort() or gsl_thread_wakeup()).
  664. */
  665. void
  666. gsl_thread_get_pollfd (GPollFD *pfd)
  667. {
  668. ThreadData *tdata = thread_data_from_gsl_thread (gsl_thread_self ());
  669. pfd->fd = tdata->wpipe[0];
  670. pfd->events = G_IO_IN;
  671. pfd->revents = 0;
  672. }
  673. /**
  674. * gsl_thread_awake_after
  675. * @tick_stamp: tick stamp update to trigger wakeup
  676. * Wakeup the currently running thread after the global tick stamp
  677. * (see gsl_tick_stamp()) has been updated to @tick_stamp.
  678. * (If the moment of wakeup has already passed by, the thread is
  679. * woken up at the next global tick stamp update.)
  680. */
  681. void
  682. gsl_thread_awake_after (guint64 tick_stamp)
  683. {
  684. ThreadData *tdata = thread_data_from_gsl_thread (gsl_thread_self ());
  685. g_return_if_fail (tick_stamp > 0);
  686. GSL_SYNC_LOCK (&global_thread);
  687. if (!tdata->awake_stamp)
  688. {
  689. awake_tdata_list = gsl_ring_prepend (awake_tdata_list, tdata);
  690. tdata->awake_stamp = tick_stamp;
  691. }
  692. else
  693. tdata->awake_stamp = MIN (tdata->awake_stamp, tick_stamp);
  694. GSL_SYNC_UNLOCK (&global_thread);
  695. }
  696. /**
  697. * gsl_thread_awake_before
  698. * @tick_stamp: tick stamp update to trigger wakeup
  699. * Wakeup the currently running thread upon the last global tick stamp
  700. * update (see gsl_tick_stamp()) that happens prior to updating the
  701. * global tick stamp to @tick_stamp.
  702. * (If the moment of wakeup has already passed by, the thread is
  703. * woken up at the next global tick stamp update.)
  704. */
  705. void
  706. gsl_thread_awake_before (guint64 tick_stamp)
  707. {
  708. g_return_if_fail (tick_stamp > 0);
  709. if (tick_stamp > global_tick_stamp_leaps)
  710. gsl_thread_awake_after (tick_stamp - global_tick_stamp_leaps);
  711. else
  712. gsl_thread_awake_after (tick_stamp);
  713. }
  714. /**
  715. * gsl_tick_stamp
  716. * @RETURNS: GSL's execution tick stamp as unsigned 64bit integer
  717. *
  718. * Retrive the GSL global tick stamp.
  719. * GSL increments its global tick stamp at certain intervals,
  720. * by specific amounts (refer to gsl_engine_init() for further
  721. * details). The tick stamp is a non-wrapping, unsigned 64bit
  722. * integer greater than 0. Threads can schedule sleep interruptions
  723. * at certain tick stamps with gsl_thread_awake_after() and
  724. * gsl_thread_awake_before(). Tick stamp updating occours at
  725. * GSL engine block processing boundaries, so code that can
  726. * guarantee to not run across those boundaries (for instance
  727. * GslProcessFunc() functions) may use the macro %GSL_TICK_STAMP
  728. * to retrive the current tick in a faster manner (not involving
  729. * mutex locking). See also gsl_module_tick_stamp().
  730. * This function is MT-safe and may be called from any thread.
  731. */
  732. guint64
  733. gsl_tick_stamp (void)
  734. {
  735. guint64 stamp;
  736. GSL_SYNC_LOCK (&global_thread);
  737. stamp = gsl_externvar_tick_stamp;
  738. GSL_SYNC_UNLOCK (&global_thread);
  739. return stamp;
  740. }
  741. void
  742. _gsl_tick_stamp_set_leap (guint ticks)
  743. {
  744. GSL_SYNC_LOCK (&global_thread);
  745. global_tick_stamp_leaps = ticks;
  746. GSL_SYNC_UNLOCK (&global_thread);
  747. }
  748. /**
  749. * gsl_time_system
  750. * @RETURNS: Current system time in micro seconds
  751. *
  752. * Get the current system time in micro seconds.
  753. * Subsequent calls to this function do not necessarily
  754. * return growing values. In fact, a second call may return
  755. * a value smaller than the first call under certainsystem
  756. * conditions.
  757. * This function is MT-safe and may be called from any thread.
  758. */
  759. guint64
  760. gsl_time_system (void)
  761. {
  762. struct timeval tv;
  763. guint64 csys_time;
  764. gint error;
  765. error = gettimeofday (&tv, NULL);
  766. if (error)
  767. g_error ("gettimeofday() failed: %s", g_strerror (errno));
  768. csys_time = tv.tv_sec;
  769. csys_time = csys_time * 1000000 + tv.tv_usec;
  770. return csys_time;
  771. }
  772. /**
  773. * gsl_tick_stamp_last
  774. * @RETURNS: Current tick stamp and system time in micro seconds
  775. *
  776. * Get the system time of the last GSL global tick stamp update.
  777. * This function is MT-safe and may be called from any thread.
  778. */
  779. GslTickStampUpdate
  780. gsl_tick_stamp_last (void)
  781. {
  782. GslTickStampUpdate ustamp;
  783. GSL_SYNC_LOCK (&global_thread);
  784. ustamp.tick_stamp = gsl_externvar_tick_stamp;
  785. ustamp.system_time = tick_stamp_system_time;
  786. GSL_SYNC_UNLOCK (&global_thread);
  787. return ustamp;
  788. }
  789. void
  790. _gsl_tick_stamp_inc (void)
  791. {
  792. volatile guint64 newstamp;
  793. GslRing *ring;
  794. guint64 systime;
  795. g_return_if_fail (global_tick_stamp_leaps > 0);
  796. systime = gsl_time_system ();
  797. newstamp = gsl_externvar_tick_stamp + global_tick_stamp_leaps;
  798. GSL_SYNC_LOCK (&global_thread);
  799. gsl_externvar_tick_stamp = newstamp;
  800. tick_stamp_system_time = systime;
  801. for (ring = awake_tdata_list; ring; )
  802. {
  803. ThreadData *tdata = ring->data;
  804. if (tdata->awake_stamp <= GSL_TICK_STAMP)
  805. {
  806. GslRing *next = gsl_ring_walk (awake_tdata_list, ring);
  807. tdata->awake_stamp = 0;
  808. awake_tdata_list = gsl_ring_remove (awake_tdata_list, tdata);
  809. thread_wakeup_I (tdata);
  810. ring = next;
  811. }
  812. else
  813. ring = gsl_ring_walk (awake_tdata_list, ring);
  814. }
  815. GSL_SYNC_UNLOCK (&global_thread);
  816. }
  817. /* --- GslMutex --- */
  818. static gboolean is_smp_system = FALSE;
  819. static void
  820. default_mutex_init (GslMutex *mutex)
  821. {
  822. g_return_if_fail (mutex != NULL);
  823. mutex->mutex_pointer = g_mutex_new ();
  824. }
  825. static int
  826. default_mutex_trylock (GslMutex *mutex)
  827. {
  828. return g_mutex_trylock (mutex->mutex_pointer) ? 0 : -1;
  829. }
  830. static void
  831. default_mutex_lock (GslMutex *mutex)
  832. {
  833. /* spin locks should be held only very short times,
  834. * so frequently we should succeed here
  835. */
  836. if (g_mutex_trylock (mutex->mutex_pointer))
  837. return;
  838. if (!is_smp_system)
  839. {
  840. /* on uni processor systems, there's no point in busy spinning */
  841. do
  842. {
  843. #if defined(_POSIX_PRIORITY_SCHEDULING)
  844. sched_yield ();
  845. #endif
  846. if (g_mutex_trylock (mutex->mutex_pointer))
  847. return;
  848. }
  849. while (TRUE);
  850. }
  851. else
  852. {
  853. /* for multi processor systems, mutex_lock() is hopefully implemented
  854. * via spinning. note that we can't implement spinning ourselves with
  855. * mutex_trylock(), since on some architectures that'd block memory
  856. * bandwith due to constant bus locks
  857. */
  858. g_mutex_lock (mutex->mutex_pointer);
  859. }
  860. }
  861. static void
  862. default_mutex_unlock (GslMutex *mutex)
  863. {
  864. g_mutex_unlock (mutex->mutex_pointer);
  865. }
  866. static void
  867. default_mutex_destroy (GslMutex *mutex)
  868. {
  869. g_mutex_free (mutex->mutex_pointer);
  870. memset (mutex, 0, sizeof (*mutex));
  871. }
  872. static void
  873. default_rec_mutex_init (GslRecMutex *rec_mutex)
  874. {
  875. rec_mutex->depth = 0;
  876. rec_mutex->owner = NULL;
  877. gsl_mutex_init (&rec_mutex->sync_mutex);
  878. }
  879. static int
  880. default_rec_mutex_trylock (GslRecMutex *rec_mutex)
  881. {
  882. gpointer self = gsl_thread_self ();
  883. if (rec_mutex->owner == self)
  884. {
  885. g_assert (rec_mutex->depth > 0); /* paranoid */
  886. rec_mutex->depth += 1;
  887. return 0;
  888. }
  889. else
  890. {
  891. if (gsl_mutex_trylock (&rec_mutex->sync_mutex))
  892. {
  893. g_assert (rec_mutex->owner == NULL && rec_mutex->depth == 0); /* paranoid */
  894. rec_mutex->owner = self;
  895. rec_mutex->depth = 1;
  896. return 0;
  897. }
  898. }
  899. return -1;
  900. }
  901. static void
  902. default_rec_mutex_lock (GslRecMutex *rec_mutex)
  903. {
  904. gpointer self = gsl_thread_self ();
  905. if (rec_mutex->owner == self)
  906. {
  907. g_assert (rec_mutex->depth > 0); /* paranoid */
  908. rec_mutex->depth += 1;
  909. }
  910. else
  911. {
  912. GSL_SYNC_LOCK (&rec_mutex->sync_mutex);
  913. g_assert (rec_mutex->owner == NULL && rec_mutex->depth == 0); /* paranoid */
  914. rec_mutex->owner = self;
  915. rec_mutex->depth = 1;
  916. }
  917. }
  918. static void
  919. default_rec_mutex_unlock (GslRecMutex *rec_mutex)
  920. {
  921. gpointer self = gsl_thread_self ();
  922. if (rec_mutex->owner == self && rec_mutex->depth > 0)
  923. {
  924. rec_mutex->depth -= 1;
  925. if (!rec_mutex->depth)
  926. {
  927. rec_mutex->owner = NULL;
  928. GSL_SYNC_UNLOCK (&rec_mutex->sync_mutex);
  929. }
  930. }
  931. else
  932. g_warning ("unable to unlock recursive mutex with self %p != %p or depth %u < 1",
  933. rec_mutex->owner, self, rec_mutex->depth);
  934. }
  935. static void
  936. default_rec_mutex_destroy (GslRecMutex *rec_mutex)
  937. {
  938. if (rec_mutex->owner || rec_mutex->depth)
  939. {
  940. g_warning (G_STRLOC ": recursive mutex still locked during destruction");
  941. return;
  942. }
  943. gsl_mutex_destroy (&rec_mutex->sync_mutex);
  944. g_assert (rec_mutex->owner == NULL && rec_mutex->depth == 0);
  945. }
  946. static void
  947. default_cond_init (GslCond *cond)
  948. {
  949. cond->cond_pointer = g_cond_new ();
  950. }
  951. static void
  952. default_cond_wait (GslCond *cond,
  953. GslMutex *mutex)
  954. {
  955. /* infinite wait */
  956. g_cond_wait (cond->cond_pointer, mutex->mutex_pointer);
  957. }
  958. static void
  959. default_cond_signal (GslCond *cond)
  960. {
  961. g_cond_signal (cond->cond_pointer);
  962. }
  963. static void
  964. default_cond_broadcast (GslCond *cond)
  965. {
  966. g_cond_broadcast (cond->cond_pointer);
  967. }
  968. static void
  969. default_cond_destroy (GslCond *cond)
  970. {
  971. g_cond_free (cond->cond_pointer);
  972. }
  973. static void
  974. default_cond_wait_timed (GslCond *cond,
  975. GslMutex *mutex,
  976. gulong abs_secs,
  977. gulong abs_usecs)
  978. {
  979. GTimeVal gtime;
  980. gtime.tv_sec = abs_secs;
  981. gtime.tv_usec = abs_usecs;
  982. g_cond_timed_wait (cond->cond_pointer, mutex->mutex_pointer, &gtime);
  983. }
  984. GslMutexTable gsl_mutex_table = {
  985. default_mutex_init,
  986. default_mutex_lock,
  987. default_mutex_trylock,
  988. default_mutex_unlock,
  989. default_mutex_destroy,
  990. default_rec_mutex_init,
  991. default_rec_mutex_lock,
  992. default_rec_mutex_trylock,
  993. default_rec_mutex_unlock,
  994. default_rec_mutex_destroy,
  995. default_cond_init,
  996. default_cond_signal,
  997. default_cond_broadcast,
  998. default_cond_wait,
  999. default_cond_wait_timed,
  1000. default_cond_destroy,
  1001. };
  1002. void
  1003. gsl_cond_wait_timed (GslCond *cond,
  1004. GslMutex *mutex,
  1005. glong max_useconds)
  1006. {
  1007. if (max_useconds < 0)
  1008. gsl_cond_wait (cond, mutex);
  1009. else
  1010. {
  1011. struct timeval now;
  1012. glong secs;
  1013. gettimeofday (&now, NULL);
  1014. secs = max_useconds / 1000000;
  1015. now.tv_sec += secs;
  1016. max_useconds -= secs * 1000000;
  1017. now.tv_usec += max_useconds;
  1018. if (now.tv_usec >= 1000000)
  1019. {
  1020. now.tv_usec -= 1000000;
  1021. now.tv_sec += 1;
  1022. }
  1023. /* linux on x86 with pthread has actually 10ms resolution */
  1024. gsl_mutex_table.cond_wait_timed (cond, mutex, now.tv_sec, now.tv_usec);
  1025. }
  1026. }
  1027. /* --- GslMessage --- */
  1028. const gchar*
  1029. gsl_strerror (GslErrorType error)
  1030. {
  1031. switch (error)
  1032. {
  1033. case GSL_ERROR_NONE: return "Everything went well";
  1034. case GSL_ERROR_INTERNAL: return "Internal error (please report)";
  1035. case GSL_ERROR_UNKNOWN: return "Unknown error";
  1036. case GSL_ERROR_IO: return "I/O error";
  1037. case GSL_ERROR_PERMS: return "Insufficient permission";
  1038. case GSL_ERROR_BUSY: return "Resource currently busy";
  1039. case GSL_ERROR_EXISTS: return "Resource exists already";
  1040. case GSL_ERROR_TEMP: return "Temporary error";
  1041. case GSL_ERROR_EOF: return "File empty or premature EOF";
  1042. case GSL_ERROR_NOT_FOUND: return "Resource not found";
  1043. case GSL_ERROR_OPEN_FAILED: return "Open failed";
  1044. case GSL_ERROR_SEEK_FAILED: return "Seek failed";
  1045. case GSL_ERROR_READ_FAILED: return "Read failed";
  1046. case GSL_ERROR_WRITE_FAILED: return "Write failed";
  1047. case GSL_ERROR_FORMAT_INVALID: return "Invalid format";
  1048. case GSL_ERROR_FORMAT_UNKNOWN: return "Unknown format";
  1049. case GSL_ERROR_DATA_CORRUPT: return "Data corrupt";
  1050. case GSL_ERROR_CONTENT_GLITCH: return "Data glitch (junk) detected";
  1051. case GSL_ERROR_NO_RESOURCE: return "Out of memory, disk space or similar resource";
  1052. case GSL_ERROR_CODEC_FAILURE: return "CODEC failure";
  1053. default: return NULL;
  1054. }
  1055. }
  1056. static const GDebugKey gsl_static_debug_keys[] = {
  1057. { "notify", GSL_MSG_NOTIFY },
  1058. { "dcache", GSL_MSG_DATA_CACHE },
  1059. { "dhandle", GSL_MSG_DATA_HANDLE },
  1060. { "loader", GSL_MSG_LOADER },
  1061. { "osc", GSL_MSG_OSC },
  1062. { "engine", GSL_MSG_ENGINE },
  1063. { "jobs", GSL_MSG_JOBS },
  1064. { "fjobs", GSL_MSG_FJOBS },
  1065. { "sched", GSL_MSG_SCHED },
  1066. { "master", GSL_MSG_MASTER },
  1067. { "slave", GSL_MSG_SLAVE },
  1068. };
  1069. static const gchar*
  1070. reporter_name (GslDebugFlags reporter)
  1071. {
  1072. switch (reporter)
  1073. {
  1074. case GSL_MSG_NOTIFY: return "Notify";
  1075. case GSL_MSG_DATA_CACHE: return "DataCache";
  1076. case GSL_MSG_DATA_HANDLE: return "DataHandle";
  1077. case GSL_MSG_LOADER: return "Loader";
  1078. case GSL_MSG_OSC: return "Oscillator";
  1079. case GSL_MSG_ENGINE: return "Engine"; /* Engine */
  1080. case GSL_MSG_JOBS: return "Jobs"; /* Engine */
  1081. case GSL_MSG_FJOBS: return "FlowJobs"; /* Engine */
  1082. case GSL_MSG_SCHED: return "Sched"; /* Engine */
  1083. case GSL_MSG_MASTER: return "Master"; /* Engine */
  1084. case GSL_MSG_SLAVE: return "Slave"; /* Engine */
  1085. default: return "Custom";
  1086. }
  1087. }
  1088. const GDebugKey *gsl_debug_keys = gsl_static_debug_keys;
  1089. const guint gsl_n_debug_keys = G_N_ELEMENTS (gsl_static_debug_keys);
  1090. void
  1091. gsl_message_send (GslDebugFlags reporter,
  1092. const gchar *section,
  1093. GslErrorType error,
  1094. const gchar *messagef,
  1095. ...)
  1096. {
  1097. struct {
  1098. GslDebugFlags reporter;
  1099. gchar reporter_name[64];
  1100. gchar section[64]; /* auxillary information about reporter code portion */
  1101. GslErrorType error;
  1102. const gchar *error_str; /* gsl_strerror() of error */
  1103. gchar message[1024];
  1104. } tmsg, *msg = &tmsg;
  1105. gchar *string;
  1106. va_list args;
  1107. g_return_if_fail (messagef != NULL);
  1108. /* create message */
  1109. memset (msg, 0, sizeof (*msg));
  1110. msg->reporter = reporter;
  1111. strncpy (msg->reporter_name, reporter_name (msg->reporter), 63);
  1112. if (section)
  1113. strncpy (msg->section, section, 63);
  1114. msg->error = error;
  1115. msg->error_str = error ? gsl_strerror (msg->error) : NULL;
  1116. /* vsnprintf() replacement */
  1117. va_start (args, messagef);
  1118. string = g_strdup_vprintf (messagef, args);
  1119. va_end (args);
  1120. strncpy (msg->message, string, 1023);
  1121. g_free (string);
  1122. /* in current lack of a decent message queue, puke the message to stderr */
  1123. g_printerr ("GSL-%s%s%s: %s%s%s\n",
  1124. msg->reporter_name,
  1125. msg->section ? ":" : "",
  1126. msg->section ? msg->section : "",
  1127. msg->message,
  1128. msg->error_str ? ": " : "",
  1129. msg->error_str ? msg->error_str : "");
  1130. }
  1131. void
  1132. gsl_debug_enable (GslDebugFlags dbg_flags)
  1133. {
  1134. gsl_debug_flags |= dbg_flags;
  1135. }
  1136. void
  1137. gsl_debug_disable (GslDebugFlags dbg_flags)
  1138. {
  1139. gsl_debug_flags &= dbg_flags;
  1140. }
  1141. gboolean
  1142. gsl_debug_check (GslDebugFlags dbg_flags)
  1143. {
  1144. return (gsl_debug_flags & dbg_flags) != 0;
  1145. }
  1146. void
  1147. gsl_debug (GslDebugFlags reporter,
  1148. const gchar *section,
  1149. const gchar *format,
  1150. ...)
  1151. {
  1152. g_return_if_fail (format != NULL);
  1153. if (reporter & gsl_debug_flags)
  1154. {
  1155. va_list args;
  1156. gchar *string;
  1157. va_start (args, format);
  1158. string = g_strdup_vprintf (format, args);
  1159. va_end (args);
  1160. g_printerr ("DEBUG:GSL-%s%s%s: %s\n",
  1161. reporter_name (reporter),
  1162. section ? ":" : "",
  1163. section ? section : "",
  1164. string);
  1165. g_free (string);
  1166. }
  1167. }
  1168. void
  1169. gsl_auxlog_push (GslDebugFlags reporter,
  1170. const gchar *section)
  1171. {
  1172. ThreadData *tdata = thread_data_from_gsl_thread (gsl_thread_self ());
  1173. if (tdata)
  1174. {
  1175. tdata->auxlog_reporter = reporter;
  1176. tdata->auxlog_section = section;
  1177. }
  1178. }
  1179. void
  1180. gsl_auxlog_debug (const gchar *format,
  1181. ...)
  1182. {
  1183. ThreadData *tdata = thread_data_from_gsl_thread (gsl_thread_self ());
  1184. GslDebugFlags reporter = GSL_MSG_NOTIFY;
  1185. const gchar *section = NULL;
  1186. va_list args;
  1187. gchar *string;
  1188. if (tdata)
  1189. {
  1190. reporter = tdata->auxlog_reporter;
  1191. section = tdata->auxlog_section;
  1192. tdata->auxlog_reporter = 0;
  1193. tdata->auxlog_section = NULL;
  1194. }
  1195. g_return_if_fail (format != NULL);
  1196. va_start (args, format);
  1197. string = g_strdup_vprintf (format, args);
  1198. va_end (args);
  1199. gsl_debug (reporter, section, "%s", string);
  1200. g_free (string);
  1201. }
  1202. void
  1203. gsl_auxlog_message (GslErrorType error,
  1204. const gchar *format,
  1205. ...)
  1206. {
  1207. ThreadData *tdata = thread_data_from_gsl_thread (gsl_thread_self ());
  1208. GslDebugFlags reporter = GSL_MSG_NOTIFY;
  1209. const gchar *section = NULL;
  1210. va_list args;
  1211. gchar *string;
  1212. if (tdata)
  1213. {
  1214. reporter = tdata->auxlog_reporter;
  1215. section = tdata->auxlog_section;
  1216. tdata->auxlog_reporter = 0;
  1217. tdata->auxlog_section = NULL;
  1218. }
  1219. g_return_if_fail (format != NULL);
  1220. va_start (args, format);
  1221. string = g_strdup_vprintf (format, args);
  1222. va_end (args);
  1223. gsl_message_send (reporter, section, error, "%s", string);
  1224. g_free (string);
  1225. }
  1226. /* --- misc --- */
  1227. const gchar*
  1228. gsl_byte_order_to_string (guint byte_order)
  1229. {
  1230. g_return_val_if_fail (byte_order == G_LITTLE_ENDIAN || byte_order == G_BIG_ENDIAN, NULL);
  1231. if (byte_order == G_LITTLE_ENDIAN)
  1232. return "little_endian";
  1233. if (byte_order == G_BIG_ENDIAN)
  1234. return "big_endian";
  1235. return NULL;
  1236. }
  1237. guint
  1238. gsl_byte_order_from_string (const gchar *string)
  1239. {
  1240. g_return_val_if_fail (string != NULL, 0);
  1241. while (*string == ' ')
  1242. string++;
  1243. if (strncasecmp (string, "little", 6) == 0)
  1244. return G_LITTLE_ENDIAN;
  1245. if (strncasecmp (string, "big", 3) == 0)
  1246. return G_BIG_ENDIAN;
  1247. return 0;
  1248. }
  1249. GslErrorType
  1250. gsl_check_file (const gchar *file_name,
  1251. const gchar *mode)
  1252. {
  1253. guint access_tqmask = 0;
  1254. guint check_file, check_dir, check_link;
  1255. if (strchr (mode, 'r')) /* readable */
  1256. access_tqmask |= R_OK;
  1257. if (strchr (mode, 'w')) /* writable */
  1258. access_tqmask |= W_OK;
  1259. if (strchr (mode, 'x')) /* executable */
  1260. access_tqmask |= X_OK;
  1261. if (access_tqmask && access (file_name, access_tqmask) < 0)
  1262. goto have_errno;
  1263. check_file = strchr (mode, 'f') != NULL; /* open as file */
  1264. check_dir = strchr (mode, 'd') != NULL; /* open as directory */
  1265. check_link = strchr (mode, 'l') != NULL; /* open as link */
  1266. if (check_file || check_dir || check_link)
  1267. {
  1268. struct stat st;
  1269. if (check_link)
  1270. {
  1271. if (lstat (file_name, &st) < 0)
  1272. goto have_errno;
  1273. }
  1274. else if (stat (file_name, &st) < 0)
  1275. goto have_errno;
  1276. if ((check_file && !S_ISREG (st.st_mode)) ||
  1277. (check_dir && !S_ISDIR (st.st_mode)) ||
  1278. (check_link && !S_ISLNK (st.st_mode)))
  1279. return GSL_ERROR_OPEN_FAILED;
  1280. }
  1281. return GSL_ERROR_NONE;
  1282. have_errno:
  1283. return gsl_error_from_errno (errno, GSL_ERROR_OPEN_FAILED);
  1284. }
  1285. GslErrorType
  1286. gsl_error_from_errno (gint sys_errno,
  1287. GslErrorType fallback)
  1288. {
  1289. switch (sys_errno)
  1290. {
  1291. case ELOOP:
  1292. case ENAMETOOLONG:
  1293. case ENOTDIR:
  1294. case ENOENT: return GSL_ERROR_NOT_FOUND;
  1295. case EROFS:
  1296. case EPERM:
  1297. case EACCES: return GSL_ERROR_PERMS;
  1298. case ENOMEM:
  1299. case ENOSPC:
  1300. case EFBIG:
  1301. case ENFILE:
  1302. case EMFILE: return GSL_ERROR_NO_RESOURCE;
  1303. case EISDIR:
  1304. case ESPIPE:
  1305. case EIO: return GSL_ERROR_IO;
  1306. case EEXIST: return GSL_ERROR_EXISTS;
  1307. case ETXTBSY:
  1308. case EBUSY: return GSL_ERROR_BUSY;
  1309. case EAGAIN:
  1310. case EINTR: return GSL_ERROR_TEMP;
  1311. case EINVAL:
  1312. case EFAULT:
  1313. case EBADF: return GSL_ERROR_INTERNAL;
  1314. default: return fallback;
  1315. }
  1316. }
  1317. /* --- global initialization --- */
  1318. static guint
  1319. get_n_processors (void)
  1320. {
  1321. #ifdef _SC_NPROCESSORS_ONLN
  1322. {
  1323. gint n = sysconf (_SC_NPROCESSORS_ONLN);
  1324. if (n > 0)
  1325. return n;
  1326. }
  1327. #endif
  1328. return 1;
  1329. }
  1330. static const GslConfig *gsl_config = NULL;
  1331. const GslConfig*
  1332. gsl_get_config (void)
  1333. {
  1334. return gsl_config;
  1335. }
  1336. #define ROUND(dblval) ((GslLong) ((dblval) + .5))
  1337. void
  1338. gsl_init (const GslConfigValue values[],
  1339. GslMutexTable *mtable)
  1340. {
  1341. const GslConfigValue *config = values;
  1342. static GslConfig pconfig = { /* DEFAULTS */
  1343. 1, /* n_processors */
  1344. 2, /* wave_chunk_padding */
  1345. 4, /* wave_chunk_big_pad */
  1346. 512, /* dcache_block_size */
  1347. 1024 * 1024, /* dcache_cache_memory */
  1348. 69, /* midi_kammer_note */
  1349. 440, /* kammer_freq */
  1350. };
  1351. g_return_if_fail (gsl_config == NULL); /* assert single initialization */
  1352. /* get mutexes going first */
  1353. if (mtable)
  1354. gsl_mutex_table = *mtable;
  1355. gsl_externvar_tick_stamp = 1;
  1356. /* configure permanent config record */
  1357. if (config)
  1358. while (config->value_name)
  1359. {
  1360. if (strcmp ("wave_chunk_padding", config->value_name) == 0)
  1361. pconfig.wave_chunk_padding = ROUND (config->value);
  1362. else if (strcmp ("wave_chunk_big_pad", config->value_name) == 0)
  1363. pconfig.wave_chunk_big_pad = ROUND (config->value);
  1364. else if (strcmp ("dcache_cache_memory", config->value_name) == 0)
  1365. pconfig.dcache_cache_memory = ROUND (config->value);
  1366. else if (strcmp ("dcache_block_size", config->value_name) == 0)
  1367. pconfig.dcache_block_size = ROUND (config->value);
  1368. else if (strcmp ("midi_kammer_note", config->value_name) == 0)
  1369. pconfig.midi_kammer_note = ROUND (config->value);
  1370. else if (strcmp ("kammer_freq", config->value_name) == 0)
  1371. pconfig.kammer_freq = config->value;
  1372. config++;
  1373. }
  1374. /* constrain (user) config */
  1375. pconfig.wave_chunk_padding = MAX (1, pconfig.wave_chunk_padding);
  1376. pconfig.wave_chunk_big_pad = MAX (2 * pconfig.wave_chunk_padding, pconfig.wave_chunk_big_pad);
  1377. pconfig.dcache_block_size = MAX (2 * pconfig.wave_chunk_big_pad + sizeof (GslDataType), pconfig.dcache_block_size);
  1378. pconfig.dcache_block_size = gsl_alloc_upper_power2 (pconfig.dcache_block_size - 1);
  1379. /* pconfig.dcache_cache_memory = gsl_alloc_upper_power2 (pconfig.dcache_cache_memory); */
  1380. /* non-configurable config updates */
  1381. pconfig.n_processors = get_n_processors ();
  1382. /* export GSL configuration */
  1383. gsl_config = &pconfig;
  1384. /* initialize subsystems */
  1385. is_smp_system = GSL_CONFIG (n_processors) > 1;
  1386. gsl_mutex_init (&global_memory);
  1387. gsl_mutex_init (&global_thread);
  1388. gsl_cond_init (&global_thread_cond);
  1389. main_thread_tdata = create_tdata ();
  1390. g_assert (main_thread_tdata != NULL);
  1391. main_thread = gsl_thread_self ();
  1392. global_thread_list = gsl_ring_prepend (global_thread_list, main_thread);
  1393. _gsl_init_signal ();
  1394. _gsl_init_fd_pool ();
  1395. _gsl_init_data_caches ();
  1396. _gsl_init_engine_utils ();
  1397. _gsl_init_loader_gslwave ();
  1398. _gsl_init_loader_wav ();
  1399. _gsl_init_loader_oggvorbis ();
  1400. _gsl_init_loader_mad ();
  1401. }