Add target/hosted/unix/thread-pth.c, which is a working thread implementation
[kugel-rb.git] / uisimulator / common / io.c
blob97c64cf0a229e1925da24419a412f1f28518d89f
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Daniel Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <sys/stat.h>
27 #include <time.h>
28 #ifndef WIN32
29 #include <sys/statvfs.h>
30 #endif
32 #ifdef WIN32
33 #include <windows.h>
34 #endif
36 #ifndef _MSC_VER
37 #include <dirent.h>
38 #include <unistd.h>
39 #else
40 #include "dir-win32.h"
41 #endif
43 #define MAX_PATH 260
44 #define MAX_OPEN_FILES 11
46 #include <fcntl.h>
47 #include <SDL.h>
48 #include "thread.h"
49 #include "kernel.h"
50 #include "debug.h"
51 #include "config.h"
52 #include "ata.h" /* for IF_MV2 et al. */
53 #ifdef HAVE_GNU_PTH_THREADS
54 #include "thread-pth.h"
55 #else
56 #include "thread-sdl.h"
57 #endif
60 /* Windows (and potentially other OSes) distinguish binary and text files.
61 * Define a dummy for the others. */
62 #ifndef O_BINARY
63 #define O_BINARY 0
64 #endif
66 /* Unicode compatibility for win32 */
67 #if defined __MINGW32__
68 /* Rockbox unicode functions */
69 extern const unsigned char* utf8decode(const unsigned char *utf8,
70 unsigned short *ucs);
71 extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
73 /* Static buffers for the conversion results. This isn't thread safe,
74 * but it's sufficient for rockbox. */
75 static unsigned char convbuf1[3*MAX_PATH];
76 static unsigned char convbuf2[3*MAX_PATH];
78 static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
80 wchar_t *ucs = buffer;
82 while (*utf8)
83 utf8 = utf8decode(utf8, ucs++);
85 *ucs = 0;
86 return buffer;
88 static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
90 unsigned char *utf8 = buffer;
92 while (*ucs)
93 utf8 = utf8encode(*ucs++, utf8);
95 *utf8 = 0;
96 return buffer;
99 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
100 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
101 #define DIR_T _WDIR
102 #define DIRENT_T struct _wdirent
103 #define STAT_T struct _stat
104 extern int _wmkdir(const wchar_t*);
105 extern int _wrmdir(const wchar_t*);
106 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
107 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
108 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
109 #define READDIR(a) (_wreaddir)(a)
110 #define CLOSEDIR(a) (_wclosedir)(a)
111 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
112 /* empty variable parameter list doesn't work for variadic macros,
113 * so pretend the second parameter is variable too */
114 #define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__)
115 #define CLOSE(a) (close)(a)
116 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
117 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
119 #else /* !__MINGW32__ */
121 #define UTF8_TO_OS(a) (a)
122 #define OS_TO_UTF8(a) (a)
123 #define DIR_T DIR
124 #define DIRENT_T struct dirent
125 #define STAT_T struct stat
126 #define MKDIR(a,b) (mkdir)(a,b)
127 #define RMDIR(a) (rmdir)(a)
128 #define OPENDIR(a) (opendir)(a)
129 #define READDIR(a) (readdir)(a)
130 #define CLOSEDIR(a) (closedir)(a)
131 #define STAT(a,b) (stat)(a,b)
132 /* empty variable parameter list doesn't work for variadic macros,
133 * so pretend the second parameter is variable too */
134 #define OPEN(a, ...) (open)(a, __VA_ARGS__)
135 #define CLOSE(x) (close)(x)
136 #define REMOVE(a) (remove)(a)
137 #define RENAME(a,b) (rename)(a,b)
139 #endif /* !__MINGW32__ */
142 #ifdef HAVE_DIRCACHE
143 void dircache_remove(const char *name);
144 void dircache_rename(const char *oldname, const char *newname);
145 #endif
148 #define SIMULATOR_DEFAULT_ROOT "simdisk"
149 extern const char *sim_root_dir;
151 static int num_openfiles = 0;
153 struct sim_dirent {
154 unsigned char d_name[MAX_PATH];
155 int attribute;
156 long size;
157 long startcluster;
158 unsigned short wrtdate; /* Last write date */
159 unsigned short wrttime; /* Last write time */
162 struct dirstruct {
163 void *dir; /* actually a DIR* dir */
164 char *name;
165 } SIM_DIR;
167 struct mydir {
168 DIR_T *dir;
169 char *name;
172 typedef struct mydir MYDIR;
174 #if 1 /* maybe this needs disabling for MSVC... */
175 static unsigned int rockbox2sim(int opt)
177 int newopt = O_BINARY;
179 if(opt & 1)
180 newopt |= O_WRONLY;
181 if(opt & 2)
182 newopt |= O_RDWR;
183 if(opt & 4)
184 newopt |= O_CREAT;
185 if(opt & 8)
186 newopt |= O_APPEND;
187 if(opt & 0x10)
188 newopt |= O_TRUNC;
190 return newopt;
192 #endif
194 /** Simulator I/O engine routines **/
195 #define IO_YIELD_THRESHOLD 512
197 enum
199 IO_READ,
200 IO_WRITE,
203 struct sim_io
205 struct mutex sim_mutex; /* Rockbox mutex */
206 int cmd; /* The command to perform */
207 int ready; /* I/O ready flag - 1= ready */
208 int fd; /* The file to read/write */
209 void *buf; /* The buffer to read/write */
210 size_t count; /* Number of bytes to read/write */
211 size_t accum; /* Acculated bytes transferred */
214 static struct sim_io io;
216 int ata_init(void)
218 /* Initialize the rockbox kernel objects on a rockbox thread */
219 mutex_init(&io.sim_mutex);
220 io.accum = 0;
221 return 1;
224 int ata_spinup_time(void)
226 return HZ;
229 static ssize_t io_trigger_and_wait(int cmd)
231 void *mythread = NULL;
232 ssize_t result;
234 if (io.count > IO_YIELD_THRESHOLD ||
235 (io.accum += io.count) >= IO_YIELD_THRESHOLD)
238 * leave the cooperative threading management and let other threads
239 * interrupt us (preemptively) during IO access */
240 io.accum = 0;
241 mythread = sim_thread_unlock();
244 switch (cmd)
246 case IO_READ:
247 result = read(io.fd, io.buf, io.count);
248 break;
249 case IO_WRITE:
250 result = write(io.fd, io.buf, io.count);
251 break;
254 /* Regain our status as current */
255 if (mythread != NULL)
258 * Re-enter the cooperative threading management again */
259 sim_thread_lock(mythread);
262 return result;
265 #ifndef __PCTOOL__
266 static const char *get_sim_pathname(const char *name)
268 static char buffer[MAX_PATH]; /* sufficiently big */
270 if(name[0] == '/')
272 snprintf(buffer, sizeof(buffer), "%s%s",
273 sim_root_dir != NULL ? sim_root_dir : SIMULATOR_DEFAULT_ROOT, name);
274 return buffer;
276 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
277 return name;
279 #else
280 #define get_sim_pathname(name) name
281 #endif
283 MYDIR *sim_opendir(const char *name)
285 DIR_T *dir;
287 dir = (DIR_T *) OPENDIR(get_sim_pathname(name));
289 if (dir)
291 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
292 my->dir = dir;
293 my->name = (char *)malloc(strlen(name)+1);
294 strcpy(my->name, name);
296 return my;
298 /* failed open, return NULL */
299 return (MYDIR *)0;
302 struct sim_dirent *sim_readdir(MYDIR *dir)
304 char buffer[MAX_PATH]; /* sufficiently big */
305 static struct sim_dirent secret;
306 STAT_T s;
307 DIRENT_T *x11 = READDIR(dir->dir);
308 struct tm* tm;
310 if(!x11)
311 return (struct sim_dirent *)0;
313 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
315 /* build file name */
316 snprintf(buffer, sizeof(buffer), "%s/%s",
317 get_sim_pathname(dir->name), secret.d_name);
318 STAT(buffer, &s); /* get info */
320 #define ATTR_DIRECTORY 0x10
322 secret.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0;
323 secret.size = s.st_size;
325 tm = localtime(&(s.st_mtime));
326 secret.wrtdate = ((tm->tm_year - 80) << 9) |
327 ((tm->tm_mon + 1) << 5) |
328 tm->tm_mday;
329 secret.wrttime = (tm->tm_hour << 11) |
330 (tm->tm_min << 5) |
331 (tm->tm_sec >> 1);
332 return &secret;
335 void sim_closedir(MYDIR *dir)
337 free(dir->name);
338 CLOSEDIR(dir->dir);
340 free(dir);
343 int sim_open(const char *name, int o, ...)
345 int opts = rockbox2sim(o);
346 int ret;
347 if (num_openfiles >= MAX_OPEN_FILES)
348 return -2;
350 if (opts & O_CREAT)
352 va_list ap;
353 va_start(ap, o);
354 mode_t mode = va_arg(ap, unsigned int);
355 ret = OPEN(get_sim_pathname(name), opts, mode);
356 va_end(ap);
358 else
359 ret = OPEN(get_sim_pathname(name), opts);
361 if (ret >= 0)
362 num_openfiles++;
363 return ret;
366 int sim_close(int fd)
368 int ret;
369 ret = CLOSE(fd);
370 if (ret == 0)
371 num_openfiles--;
372 return ret;
375 int sim_creat(const char *name, mode_t mode)
377 return OPEN(get_sim_pathname(name), O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, mode);
380 ssize_t sim_read(int fd, void *buf, size_t count)
382 ssize_t result;
384 mutex_lock(&io.sim_mutex);
386 /* Setup parameters */
387 io.fd = fd;
388 io.buf = buf;
389 io.count = count;
391 result = io_trigger_and_wait(IO_READ);
393 mutex_unlock(&io.sim_mutex);
395 return result;
398 ssize_t sim_write(int fd, const void *buf, size_t count)
400 ssize_t result;
402 mutex_lock(&io.sim_mutex);
404 io.fd = fd;
405 io.buf = (void*)buf;
406 io.count = count;
408 result = io_trigger_and_wait(IO_WRITE);
410 mutex_unlock(&io.sim_mutex);
412 return result;
415 int sim_mkdir(const char *name)
417 return MKDIR(get_sim_pathname(name), 0777);
420 int sim_rmdir(const char *name)
422 return RMDIR(get_sim_pathname(name));
425 int sim_remove(const char *name)
427 #ifdef HAVE_DIRCACHE
428 dircache_remove(name);
429 #endif
430 return REMOVE(get_sim_pathname(name));
433 int sim_rename(const char *oldname, const char *newname)
435 char sim_old[MAX_PATH];
436 char sim_new[MAX_PATH];
437 #ifdef HAVE_DIRCACHE
438 dircache_rename(oldname, newname);
439 #endif
440 // This is needed as get_sim_pathname() has a static buffer
441 strncpy(sim_old, get_sim_pathname(oldname), MAX_PATH);
442 strncpy(sim_new, get_sim_pathname(newname), MAX_PATH);
443 return RENAME(sim_old, sim_new);
446 /* rockbox off_t may be different from system off_t */
447 long sim_lseek(int fildes, long offset, int whence)
449 return lseek(fildes, offset, whence);
452 long sim_filesize(int fd)
454 #ifdef WIN32
455 return _filelength(fd);
456 #else
457 struct stat buf;
459 if (!fstat(fd, &buf))
460 return buf.st_size;
461 else
462 return -1;
463 #endif
466 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
468 #ifdef HAVE_MULTIVOLUME
469 if (volume != 0) {
470 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
472 if (size) *size = 0;
473 if (free) *free = 0;
474 return;
476 #endif
478 #ifdef WIN32
479 long secperclus, bytespersec, free_clusters, num_clusters;
481 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
482 &num_clusters)) {
483 if (size)
484 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
485 if (free)
486 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
488 #else
489 struct statvfs vfs;
491 if (!statvfs(".", &vfs)) {
492 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
493 (int)vfs.f_frsize, (long)vfs.f_blocks, (long)vfs.f_bfree);
494 if (size)
495 *size = vfs.f_blocks / 2 * (vfs.f_frsize / 512);
496 if (free)
497 *free = vfs.f_bfree / 2 * (vfs.f_frsize / 512);
499 #endif
500 else {
501 if (size)
502 *size = 0;
503 if (free)
504 *free = 0;
508 int sim_fsync(int fd)
510 #ifdef WIN32
511 return _commit(fd);
512 #else
513 return fsync(fd);
514 #endif
517 #ifdef WIN32
518 /* sim-win32 */
519 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
520 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
521 #define dlclose(_x_) FreeLibrary(_x_)
522 #else
523 /* sim-x11 */
524 #include <dlfcn.h>
525 #endif
527 void *sim_codec_load_ram(char* codecptr, int size, void **pd)
529 void *hdr;
530 char name[MAX_PATH];
531 char path[MAX_PATH];
532 int fd;
533 int codec_count;
534 #ifdef WIN32
535 char buf[MAX_PATH];
536 #endif
538 *pd = NULL;
540 /* We have to create the dynamic link library file from ram so we
541 can simulate the codec loading. With voice and crossfade,
542 multiple codecs may be loaded at the same time, so we need
543 to find an unused filename */
544 for (codec_count = 0; codec_count < 10; codec_count++)
546 snprintf(name, sizeof(name), "/_temp_codec%d.dll", codec_count);
547 snprintf(path, sizeof(path), "%s", get_sim_pathname(name));
548 fd = OPEN(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRWXU);
549 if (fd >= 0)
550 break; /* Created a file ok */
552 if (fd < 0)
554 DEBUGF("failed to open for write: %s\n", path);
555 return NULL;
558 if (write(fd, codecptr, size) != size)
560 DEBUGF("write failed");
561 return NULL;
563 close(fd);
565 /* Now load the library. */
566 *pd = dlopen(path, RTLD_NOW);
567 if (*pd == NULL)
569 DEBUGF("failed to load %s\n", path);
570 #ifdef WIN32
571 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
572 buf, sizeof buf, NULL);
573 DEBUGF("dlopen(%s): %s\n", path, buf);
574 #else
575 DEBUGF("dlopen(%s): %s\n", path, dlerror());
576 #endif
577 return NULL;
580 hdr = dlsym(*pd, "__header");
581 if (!hdr)
582 hdr = dlsym(*pd, "___header");
584 return hdr; /* maybe NULL if symbol not present */
587 void sim_codec_close(void *pd)
589 dlclose(pd);
592 void *sim_plugin_load(char *plugin, void **pd)
594 void *hdr;
595 char path[MAX_PATH];
596 #ifdef WIN32
597 char buf[MAX_PATH];
598 #endif
600 snprintf(path, sizeof(path), "%s", get_sim_pathname(plugin));
602 *pd = NULL;
604 *pd = dlopen(path, RTLD_NOW);
605 if (*pd == NULL) {
606 DEBUGF("failed to load %s\n", plugin);
607 #ifdef WIN32
608 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
609 buf, sizeof(buf), NULL);
610 DEBUGF("dlopen(%s): %s\n", path, buf);
611 #else
612 DEBUGF("dlopen(%s): %s\n", path, dlerror());
613 #endif
614 return NULL;
617 hdr = dlsym(*pd, "__header");
618 if (!hdr)
619 hdr = dlsym(*pd, "___header");
621 return hdr; /* maybe NULL if symbol not present */
624 void sim_plugin_close(void *pd)
626 dlclose(pd);
629 #ifdef WIN32
630 static unsigned old_cp;
632 void debug_exit(void)
634 /* Reset console output codepage */
635 SetConsoleOutputCP(old_cp);
638 void debug_init(void)
640 old_cp = GetConsoleOutputCP();
641 /* Set console output codepage to UTF8. Only works
642 * correctly when the console uses a truetype font. */
643 SetConsoleOutputCP(65001);
644 atexit(debug_exit);
646 #else
647 void debug_init(void)
649 /* nothing to be done */
651 #endif
653 void debugf(const char *fmt, ...)
655 va_list ap;
656 va_start( ap, fmt );
657 vfprintf( stderr, fmt, ap );
658 va_end( ap );
661 void ldebugf(const char* file, int line, const char *fmt, ...)
663 va_list ap;
664 va_start( ap, fmt );
665 fprintf( stderr, "%s:%d ", file, line );
666 vfprintf( stderr, fmt, ap );
667 va_end( ap );
670 /* rockbox off_t may be different from system off_t */
671 int sim_ftruncate(int fd, long length)
673 #ifdef WIN32
674 return _chsize(fd, length);
675 #else
676 return ftruncate(fd, length);
677 #endif