branches/osd/src/osd/sdl/sdlmain.c
| r32170 | r32171 | |
| 13 | 13 | #ifdef SDLMAME_UNIX |
| 14 | 14 | #if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_EMSCRIPTEN)) |
| 15 | 15 | #if (SDLMAME_SDL2) |
| 16 | | //#include <SDL2/SDL_ttf.h> |
| 16 | #include <SDL2/SDL_ttf.h> |
| 17 | 17 | #else |
| 18 | 18 | #include <SDL/SDL_ttf.h> |
| 19 | 19 | #endif |
| r32170 | r32171 | |
| 53 | 53 | #if defined(SDLMAME_EMSCRIPTEN) |
| 54 | 54 | #include "modules/sound/js_sound.h" |
| 55 | 55 | #endif |
| 56 | #if defined(SDLMAME_WIN32) |
| 57 | #include "modules/sound/direct_sound.h" |
| 58 | #endif |
| 56 | 59 | #if !defined(NO_DEBUGGER) |
| 57 | 60 | #include "modules/debugger/debugqt.h" |
| 58 | 61 | #endif |
| r32170 | r32171 | |
| 70 | 73 | |
| 71 | 74 | #include "watchdog.h" |
| 72 | 75 | |
| 76 | #define DEFAULT_FONT_HEIGHT (200) |
| 77 | |
| 73 | 78 | //============================================================ |
| 74 | 79 | // OPTIONS |
| 75 | 80 | //============================================================ |
| r32170 | r32171 | |
| 291 | 296 | #ifdef SDLMAME_UNIX |
| 292 | 297 | sdl_entered_debugger = 0; |
| 293 | 298 | #if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_HAIKU)) && (!defined(SDLMAME_EMSCRIPTEN)) |
| 294 | | #if !(SDLMAME_SDL2) |
| 295 | 299 | if (TTF_Init() == -1) |
| 296 | 300 | { |
| 297 | 301 | printf("SDL_ttf failed: %s\n", TTF_GetError()); |
| 298 | 302 | } |
| 299 | | #endif |
| 300 | 303 | FcInit(); |
| 301 | 304 | #endif |
| 302 | 305 | #endif |
| r32170 | r32171 | |
| 344 | 347 | |
| 345 | 348 | #ifdef SDLMAME_UNIX |
| 346 | 349 | #if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_HAIKU)) && (!defined(SDLMAME_EMSCRIPTEN)) |
| 347 | | #if !(SDLMAME_SDL2) |
| 348 | 350 | TTF_Quit(); |
| 349 | | #endif |
| 350 | 351 | if (!sdl_entered_debugger) |
| 351 | 352 | { |
| 352 | 353 | FcFini(); |
| r32170 | r32171 | |
| 355 | 356 | #endif |
| 356 | 357 | |
| 357 | 358 | exit(res); |
| 358 | | |
| 359 | | return res; |
| 360 | 359 | } |
| 361 | 360 | |
| 362 | 361 | |
| r32170 | r32171 | |
| 542 | 541 | void sdl_osd_interface::sound_register() |
| 543 | 542 | { |
| 544 | 543 | sound_options_add("sdl", OSD_SOUND_SDL); |
| 544 | #if defined(SDLMAME_WIN32) |
| 545 | sound_options_add("dsound", OSD_SOUND_DIRECT_SOUND); |
| 546 | #endif |
| 547 | |
| 545 | 548 | #if defined(SDLMAME_EMSCRIPTEN) |
| 546 | 549 | sound_options_add("js", OSD_SOUND_JS); |
| 547 | 550 | sound_options_add("auto", OSD_SOUND_JS); // making JS audio default one |
| r32170 | r32171 | |
| 854 | 857 | } |
| 855 | 858 | #else // UNIX but not OSX |
| 856 | 859 | |
| 857 | | #if !(SDLMAME_SDL2) |
| 858 | 860 | static TTF_Font * TTF_OpenFont_Magic(astring name, int fsize) |
| 859 | 861 | { |
| 860 | 862 | emu_file file(OPEN_FLAG_READ); |
| r32170 | r32171 | |
| 994 | 996 | return font; |
| 995 | 997 | } |
| 996 | 998 | #endif |
| 997 | | #endif |
| 998 | 999 | |
| 999 | 1000 | //------------------------------------------------- |
| 1000 | 1001 | // font_open - attempt to "open" a handle to the |
| r32170 | r32171 | |
| 1003 | 1004 | |
| 1004 | 1005 | osd_font sdl_osd_interface::font_open(const char *_name, int &height) |
| 1005 | 1006 | { |
| 1006 | | #if !(SDLMAME_SDL2) |
| 1007 | 1007 | TTF_Font *font = (TTF_Font *)NULL; |
| 1008 | 1008 | bool bakedstyles = false; |
| 1009 | 1009 | int style = 0; |
| r32170 | r32171 | |
| 1075 | 1075 | height = TTF_FontLineSkip(font); |
| 1076 | 1076 | |
| 1077 | 1077 | return (osd_font)font; |
| 1078 | | #else |
| 1079 | | return (osd_font)NULL; |
| 1080 | | #endif |
| 1081 | 1078 | } |
| 1082 | 1079 | |
| 1083 | 1080 | //------------------------------------------------- |
| r32170 | r32171 | |
| 1087 | 1084 | |
| 1088 | 1085 | void sdl_osd_interface::font_close(osd_font font) |
| 1089 | 1086 | { |
| 1090 | | #if !(SDLMAME_SDL2) |
| 1091 | 1087 | TTF_Font *ttffont; |
| 1092 | 1088 | |
| 1093 | 1089 | ttffont = (TTF_Font *)font; |
| 1094 | 1090 | |
| 1095 | 1091 | TTF_CloseFont(ttffont); |
| 1096 | | #endif |
| 1097 | 1092 | } |
| 1098 | 1093 | |
| 1099 | 1094 | //------------------------------------------------- |
| r32170 | r32171 | |
| 1106 | 1101 | |
| 1107 | 1102 | bool sdl_osd_interface::font_get_bitmap(osd_font font, unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) |
| 1108 | 1103 | { |
| 1109 | | #if !(SDLMAME_SDL2) |
| 1110 | 1104 | TTF_Font *ttffont; |
| 1111 | 1105 | SDL_Surface *drawsurf; |
| 1112 | 1106 | SDL_Color fcol = { 0xff, 0xff, 0xff }; |
| r32170 | r32171 | |
| 1146 | 1140 | } |
| 1147 | 1141 | |
| 1148 | 1142 | return bitmap.valid(); |
| 1149 | | #else |
| 1150 | | return false; |
| 1151 | | #endif |
| 1152 | 1143 | } |
| 1153 | 1144 | #endif // not OSX |
| 1154 | 1145 | #else // not UNIX |
| 1146 | #ifdef SDLMAME_WIN32 |
| 1147 | |
| 1148 | //============================================================ |
| 1149 | // wstring_from_utf8 |
| 1150 | //============================================================ |
| 1151 | |
| 1152 | WCHAR *wstring_from_utf8(const char *utf8string) |
| 1153 | { |
| 1154 | int char_count; |
| 1155 | WCHAR *result; |
| 1156 | |
| 1157 | // convert MAME string (UTF-8) to UTF-16 |
| 1158 | char_count = MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, NULL, 0); |
| 1159 | result = (WCHAR *)osd_malloc_array(char_count * sizeof(*result)); |
| 1160 | if (result != NULL) |
| 1161 | MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, result, char_count); |
| 1162 | |
| 1163 | return result; |
| 1164 | } |
| 1165 | |
| 1166 | |
| 1167 | //============================================================ |
| 1168 | // utf8_from_wstring |
| 1169 | //============================================================ |
| 1170 | |
| 1171 | char *utf8_from_wstring(const WCHAR *wstring) |
| 1172 | { |
| 1173 | int char_count; |
| 1174 | char *result; |
| 1175 | |
| 1176 | // convert UTF-16 to MAME string (UTF-8) |
| 1177 | char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL); |
| 1178 | result = (char *)osd_malloc_array(char_count * sizeof(*result)); |
| 1179 | if (result != NULL) |
| 1180 | WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL); |
| 1181 | |
| 1182 | return result; |
| 1183 | } |
| 1184 | |
| 1185 | osd_font sdl_osd_interface::font_open(const char *_name, int &height) |
| 1186 | { |
| 1187 | // accept qualifiers from the name |
| 1188 | astring name(_name); |
| 1189 | if (name == "default") name = "Tahoma"; |
| 1190 | bool bold = (name.replace(0, "[B]", "") + name.replace(0, "[b]", "") > 0); |
| 1191 | bool italic = (name.replace(0, "[I]", "") + name.replace(0, "[i]", "") > 0); |
| 1192 | |
| 1193 | // build a basic LOGFONT description of what we want |
| 1194 | LOGFONT logfont; |
| 1195 | logfont.lfHeight = DEFAULT_FONT_HEIGHT; |
| 1196 | logfont.lfWidth = 0; |
| 1197 | logfont.lfEscapement = 0; |
| 1198 | logfont.lfOrientation = 0; |
| 1199 | logfont.lfWeight = bold ? FW_BOLD : FW_MEDIUM; |
| 1200 | logfont.lfItalic = italic; |
| 1201 | logfont.lfUnderline = FALSE; |
| 1202 | logfont.lfStrikeOut = FALSE; |
| 1203 | logfont.lfCharSet = ANSI_CHARSET; |
| 1204 | logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; |
| 1205 | logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; |
| 1206 | logfont.lfQuality = NONANTIALIASED_QUALITY; |
| 1207 | logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; |
| 1208 | |
| 1209 | // copy in the face name |
| 1210 | TCHAR *face = wstring_from_utf8(name); |
| 1211 | wcsncpy(logfont.lfFaceName, face, sizeof(logfont.lfFaceName) / sizeof(TCHAR)); |
| 1212 | logfont.lfFaceName[sizeof(logfont.lfFaceName) / sizeof(TCHAR)-1] = 0; |
| 1213 | osd_free(face); |
| 1214 | |
| 1215 | // create the font |
| 1216 | height = logfont.lfHeight; |
| 1217 | osd_font font = reinterpret_cast<osd_font>(CreateFontIndirect(&logfont)); |
| 1218 | if (font == NULL) |
| 1219 | return NULL; |
| 1220 | |
| 1221 | // select it into a temp DC and get the real font name |
| 1222 | HDC dummyDC = CreateCompatibleDC(NULL); |
| 1223 | HGDIOBJ oldfont = SelectObject(dummyDC, reinterpret_cast<HGDIOBJ>(font)); |
| 1224 | TCHAR realname[100]; |
| 1225 | GetTextFace(dummyDC, ARRAY_LENGTH(realname), realname); |
| 1226 | SelectObject(dummyDC, oldfont); |
| 1227 | DeleteDC(dummyDC); |
| 1228 | |
| 1229 | // if it doesn't match our request, fail |
| 1230 | char *utf = utf8_from_wstring(realname); |
| 1231 | int result = core_stricmp(utf, name); |
| 1232 | osd_free(utf); |
| 1233 | |
| 1234 | // if we didn't match, nuke our font and fall back |
| 1235 | if (result != 0) |
| 1236 | { |
| 1237 | DeleteObject(reinterpret_cast<HFONT>(font)); |
| 1238 | font = NULL; |
| 1239 | } |
| 1240 | return font; |
| 1241 | } |
| 1242 | |
| 1243 | |
| 1155 | 1244 | //------------------------------------------------- |
| 1245 | // font_close - release resources associated with |
| 1246 | // a given OSD font |
| 1247 | //------------------------------------------------- |
| 1248 | |
| 1249 | void sdl_osd_interface::font_close(osd_font font) |
| 1250 | { |
| 1251 | // delete the font ojbect |
| 1252 | if (font != NULL) |
| 1253 | DeleteObject(reinterpret_cast<HFONT>(font)); |
| 1254 | } |
| 1255 | |
| 1256 | |
| 1257 | //------------------------------------------------- |
| 1258 | // font_get_bitmap - allocate and populate a |
| 1259 | // BITMAP_FORMAT_ARGB32 bitmap containing the |
| 1260 | // pixel values rgb_t(0xff,0xff,0xff,0xff) |
| 1261 | // or rgb_t(0x00,0xff,0xff,0xff) for each |
| 1262 | // pixel of a black & white font |
| 1263 | //------------------------------------------------- |
| 1264 | |
| 1265 | bool sdl_osd_interface::font_get_bitmap(osd_font font, unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) |
| 1266 | { |
| 1267 | // create a dummy DC to work with |
| 1268 | HDC dummyDC = CreateCompatibleDC(NULL); |
| 1269 | HGDIOBJ oldfont = SelectObject(dummyDC, reinterpret_cast<HGDIOBJ>(font)); |
| 1270 | |
| 1271 | // get the text metrics |
| 1272 | TEXTMETRIC metrics = { 0 }; |
| 1273 | GetTextMetrics(dummyDC, &metrics); |
| 1274 | |
| 1275 | // get the width of this character |
| 1276 | ABC abc; |
| 1277 | if (!GetCharABCWidths(dummyDC, chnum, chnum, &abc)) |
| 1278 | { |
| 1279 | abc.abcA = 0; |
| 1280 | abc.abcC = 0; |
| 1281 | GetCharWidth32(dummyDC, chnum, chnum, reinterpret_cast<LPINT>(&abc.abcB)); |
| 1282 | } |
| 1283 | width = abc.abcA + abc.abcB + abc.abcC; |
| 1284 | |
| 1285 | // determine desired bitmap size |
| 1286 | int bmwidth = (50 + abc.abcA + abc.abcB + abc.abcC + 50 + 31) & ~31; |
| 1287 | int bmheight = 50 + metrics.tmHeight + 50; |
| 1288 | |
| 1289 | // describe the bitmap we want |
| 1290 | BYTE bitmapinfodata[sizeof(BITMAPINFOHEADER)+2 * sizeof(RGBQUAD)] = { 0 }; |
| 1291 | BITMAPINFO &info = *reinterpret_cast<BITMAPINFO *>(bitmapinfodata); |
| 1292 | info.bmiHeader.biSize = sizeof(info.bmiHeader); |
| 1293 | info.bmiHeader.biWidth = bmwidth; |
| 1294 | info.bmiHeader.biHeight = -bmheight; |
| 1295 | info.bmiHeader.biPlanes = 1; |
| 1296 | info.bmiHeader.biBitCount = 1; |
| 1297 | info.bmiHeader.biCompression = BI_RGB; |
| 1298 | info.bmiHeader.biSizeImage = 0; |
| 1299 | info.bmiHeader.biXPelsPerMeter = GetDeviceCaps(dummyDC, HORZRES) / GetDeviceCaps(dummyDC, HORZSIZE); |
| 1300 | info.bmiHeader.biYPelsPerMeter = GetDeviceCaps(dummyDC, VERTRES) / GetDeviceCaps(dummyDC, VERTSIZE); |
| 1301 | info.bmiHeader.biClrUsed = 0; |
| 1302 | info.bmiHeader.biClrImportant = 0; |
| 1303 | RGBQUAD col1 = info.bmiColors[0]; |
| 1304 | RGBQUAD col2 = info.bmiColors[1]; |
| 1305 | col1.rgbBlue = col1.rgbGreen = col1.rgbRed = 0x00; |
| 1306 | col2.rgbBlue = col2.rgbGreen = col2.rgbRed = 0xff; |
| 1307 | |
| 1308 | // create a DIB to render to |
| 1309 | BYTE *bits; |
| 1310 | HBITMAP dib = CreateDIBSection(dummyDC, &info, DIB_RGB_COLORS, reinterpret_cast<VOID **>(&bits), NULL, 0); |
| 1311 | HGDIOBJ oldbitmap = SelectObject(dummyDC, dib); |
| 1312 | |
| 1313 | // clear the bitmap |
| 1314 | int rowbytes = bmwidth / 8; |
| 1315 | memset(bits, 0, rowbytes * bmheight); |
| 1316 | |
| 1317 | // now draw the character |
| 1318 | WCHAR tempchar = chnum; |
| 1319 | SetTextColor(dummyDC, RGB(0xff, 0xff, 0xff)); |
| 1320 | SetBkColor(dummyDC, RGB(0x00, 0x00, 0x00)); |
| 1321 | ExtTextOutW(dummyDC, 50 + abc.abcA, 50, ETO_OPAQUE, NULL, &tempchar, 1, NULL); |
| 1322 | |
| 1323 | // characters are expected to be full-height |
| 1324 | rectangle actbounds; |
| 1325 | actbounds.min_y = 50; |
| 1326 | actbounds.max_y = 50 + metrics.tmHeight - 1; |
| 1327 | |
| 1328 | // determine the actual left of the character |
| 1329 | for (actbounds.min_x = 0; actbounds.min_x < rowbytes; actbounds.min_x++) |
| 1330 | { |
| 1331 | BYTE *offs = bits + actbounds.min_x; |
| 1332 | UINT8 summary = 0; |
| 1333 | for (int y = 0; y < bmheight; y++) |
| 1334 | summary |= offs[y * rowbytes]; |
| 1335 | if (summary != 0) |
| 1336 | { |
| 1337 | actbounds.min_x *= 8; |
| 1338 | if (!(summary & 0x80)) actbounds.min_x++; |
| 1339 | if (!(summary & 0xc0)) actbounds.min_x++; |
| 1340 | if (!(summary & 0xe0)) actbounds.min_x++; |
| 1341 | if (!(summary & 0xf0)) actbounds.min_x++; |
| 1342 | if (!(summary & 0xf8)) actbounds.min_x++; |
| 1343 | if (!(summary & 0xfc)) actbounds.min_x++; |
| 1344 | if (!(summary & 0xfe)) actbounds.min_x++; |
| 1345 | break; |
| 1346 | } |
| 1347 | } |
| 1348 | |
| 1349 | // determine the actual right of the character |
| 1350 | for (actbounds.max_x = rowbytes - 1; actbounds.max_x >= 0; actbounds.max_x--) |
| 1351 | { |
| 1352 | BYTE *offs = bits + actbounds.max_x; |
| 1353 | UINT8 summary = 0; |
| 1354 | for (int y = 0; y < bmheight; y++) |
| 1355 | summary |= offs[y * rowbytes]; |
| 1356 | if (summary != 0) |
| 1357 | { |
| 1358 | actbounds.max_x *= 8; |
| 1359 | if (summary & 0x7f) actbounds.max_x++; |
| 1360 | if (summary & 0x3f) actbounds.max_x++; |
| 1361 | if (summary & 0x1f) actbounds.max_x++; |
| 1362 | if (summary & 0x0f) actbounds.max_x++; |
| 1363 | if (summary & 0x07) actbounds.max_x++; |
| 1364 | if (summary & 0x03) actbounds.max_x++; |
| 1365 | if (summary & 0x01) actbounds.max_x++; |
| 1366 | break; |
| 1367 | } |
| 1368 | } |
| 1369 | |
| 1370 | // allocate a new bitmap |
| 1371 | if (actbounds.max_x >= actbounds.min_x && actbounds.max_y >= actbounds.min_y) |
| 1372 | { |
| 1373 | bitmap.allocate(actbounds.max_x + 1 - actbounds.min_x, actbounds.max_y + 1 - actbounds.min_y); |
| 1374 | |
| 1375 | // copy the bits into it |
| 1376 | for (int y = 0; y < bitmap.height(); y++) |
| 1377 | { |
| 1378 | UINT32 *dstrow = &bitmap.pix32(y); |
| 1379 | UINT8 *srcrow = &bits[(y + actbounds.min_y) * rowbytes]; |
| 1380 | for (int x = 0; x < bitmap.width(); x++) |
| 1381 | { |
| 1382 | int effx = x + actbounds.min_x; |
| 1383 | dstrow[x] = ((srcrow[effx / 8] << (effx % 8)) & 0x80) ? rgb_t(0xff, 0xff, 0xff, 0xff) : rgb_t(0x00, 0xff, 0xff, 0xff); |
| 1384 | } |
| 1385 | } |
| 1386 | |
| 1387 | // set the final offset values |
| 1388 | xoffs = actbounds.min_x - (50 + abc.abcA); |
| 1389 | yoffs = actbounds.max_y - (50 + metrics.tmAscent); |
| 1390 | } |
| 1391 | |
| 1392 | // de-select the font and release the DC |
| 1393 | SelectObject(dummyDC, oldbitmap); |
| 1394 | DeleteObject(dib); |
| 1395 | SelectObject(dummyDC, oldfont); |
| 1396 | DeleteDC(dummyDC); |
| 1397 | return bitmap.valid(); |
| 1398 | } |
| 1399 | |
| 1400 | #else |
| 1401 | |
| 1402 | //------------------------------------------------- |
| 1156 | 1403 | // font_open - attempt to "open" a handle to the |
| 1157 | 1404 | // font with the given name |
| 1158 | 1405 | //------------------------------------------------- |
| r32170 | r32171 | |
| 1184 | 1431 | return false; |
| 1185 | 1432 | } |
| 1186 | 1433 | #endif |
| 1434 | #endif |
branches/osd/src/osd/sdl/sdlsync_win32.c
| r32170 | r32171 | |
| 9 | 9 | // |
| 10 | 10 | //============================================================ |
| 11 | 11 | |
| 12 | | #define WIN32_LEAN_AND_MEAN |
| 13 | | #include <windows.h> |
| 14 | | #include <process.h> |
| 15 | | #include <tchar.h> |
| 16 | | |
| 17 | | #ifdef __GNUC__ |
| 18 | | #include <stdint.h> |
| 19 | | #endif |
| 20 | | |
| 21 | | // MAME headers |
| 22 | | #include "osdcore.h" |
| 23 | | #include "osinline.h" |
| 24 | | #include "sdlsync.h" |
| 25 | | |
| 26 | | #include "../windows/winsync.c" |
| 27 | | |
| 28 | | |
| 29 | | //============================================================ |
| 30 | | // DEBUGGING |
| 31 | | //============================================================ |
| 32 | | |
| 33 | | #define USE_SCALABLE_LOCKS (0) |
| 34 | | |
| 35 | | struct osd_event |
| 36 | | { |
| 37 | | void * ptr; |
| 38 | | }; |
| 39 | | |
| 40 | | struct osd_thread { |
| 41 | | HANDLE handle; |
| 42 | | osd_thread_callback callback; |
| 43 | | void *param; |
| 44 | | }; |
| 45 | | |
| 46 | | //============================================================ |
| 47 | | // osd_event_alloc |
| 48 | | //============================================================ |
| 49 | | |
| 50 | | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 51 | | { |
| 52 | | return (osd_event *) CreateEvent(NULL, manualreset, initialstate, NULL); |
| 53 | | } |
| 54 | | |
| 55 | | //============================================================ |
| 56 | | // osd_event_free |
| 57 | | //============================================================ |
| 58 | | |
| 59 | | void osd_event_free(osd_event *event) |
| 60 | | { |
| 61 | | CloseHandle((HANDLE) event); |
| 62 | | } |
| 63 | | |
| 64 | | //============================================================ |
| 65 | | // osd_event_set |
| 66 | | //============================================================ |
| 67 | | |
| 68 | | void osd_event_set(osd_event *event) |
| 69 | | { |
| 70 | | SetEvent((HANDLE) event); |
| 71 | | } |
| 72 | | |
| 73 | | //============================================================ |
| 74 | | // osd_event_reset |
| 75 | | //============================================================ |
| 76 | | |
| 77 | | void osd_event_reset(osd_event *event) |
| 78 | | { |
| 79 | | ResetEvent((HANDLE) event); |
| 80 | | } |
| 81 | | |
| 82 | | //============================================================ |
| 83 | | // osd_event_wait |
| 84 | | //============================================================ |
| 85 | | |
| 86 | | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 87 | | { |
| 88 | | int ret = WaitForSingleObject((HANDLE) event, timeout * 1000 / osd_ticks_per_second()); |
| 89 | | return ( ret == WAIT_OBJECT_0); |
| 90 | | } |
| 91 | | |
| 92 | | //============================================================ |
| 93 | | // Scalable Locks |
| 94 | | //============================================================ |
| 95 | | |
| 96 | | struct osd_scalable_lock |
| 97 | | { |
| 98 | | #if USE_SCALABLE_LOCKS |
| 99 | | struct |
| 100 | | { |
| 101 | | volatile INT32 haslock; // do we have the lock? |
| 102 | | INT32 filler[64/4-1]; // assumes a 64-byte cache line |
| 103 | | } slot[WORK_MAX_THREADS]; // one slot per thread |
| 104 | | volatile INT32 nextindex; // index of next slot to use |
| 105 | | #else |
| 106 | | CRITICAL_SECTION section; |
| 107 | | #endif |
| 108 | | }; |
| 109 | | |
| 110 | | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 111 | | { |
| 112 | | osd_scalable_lock *lock; |
| 113 | | |
| 114 | | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 115 | | |
| 116 | | memset(lock, 0, sizeof(*lock)); |
| 117 | | #if USE_SCALABLE_LOCKS |
| 118 | | lock->slot[0].haslock = TRUE; |
| 119 | | #else |
| 120 | | InitializeCriticalSection(&lock->section); |
| 121 | | #endif |
| 122 | | return lock; |
| 123 | | } |
| 124 | | |
| 125 | | |
| 126 | | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 127 | | { |
| 128 | | #if USE_SCALABLE_LOCKS |
| 129 | | INT32 myslot = (interlocked_increment(&lock->nextindex) - 1) & (WORK_MAX_THREADS - 1); |
| 130 | | INT32 backoff = 1; |
| 131 | | |
| 132 | | while (!lock->slot[myslot].haslock) |
| 133 | | { |
| 134 | | INT32 backcount; |
| 135 | | for (backcount = 0; backcount < backoff; backcount++) |
| 136 | | YieldProcessor(); |
| 137 | | backoff <<= 1; |
| 138 | | } |
| 139 | | lock->slot[myslot].haslock = FALSE; |
| 140 | | return myslot; |
| 141 | | #else |
| 142 | | EnterCriticalSection(&lock->section); |
| 143 | | return 0; |
| 144 | | #endif |
| 145 | | } |
| 146 | | |
| 147 | | |
| 148 | | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 149 | | { |
| 150 | | #if USE_SCALABLE_LOCKS |
| 151 | | interlocked_exchange32(&lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock, TRUE); |
| 152 | | #else |
| 153 | | LeaveCriticalSection(&lock->section); |
| 154 | | #endif |
| 155 | | } |
| 156 | | |
| 157 | | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 158 | | { |
| 159 | | free(lock); |
| 160 | | } |
| 161 | | |
| 162 | | //============================================================ |
| 163 | | // osd_thread_create |
| 164 | | //============================================================ |
| 165 | | |
| 166 | | static unsigned __stdcall worker_thread_entry(void *param) |
| 167 | | { |
| 168 | | osd_thread *thread = (osd_thread *) param; |
| 169 | | void *res; |
| 170 | | res = thread->callback(thread->param); |
| 171 | | #ifdef PTR64 |
| 172 | | return (unsigned) (long long) res; |
| 173 | | #else |
| 174 | | return (unsigned) res; |
| 175 | | #endif |
| 176 | | } |
| 177 | | |
| 178 | | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 179 | | { |
| 180 | | osd_thread *thread; |
| 181 | | uintptr_t handle; |
| 182 | | |
| 183 | | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 184 | | thread->callback = callback; |
| 185 | | thread->param = cbparam; |
| 186 | | handle = _beginthreadex(NULL, 0, worker_thread_entry, thread, 0, NULL); |
| 187 | | thread->handle = (HANDLE) handle; |
| 188 | | return thread; |
| 189 | | } |
| 190 | | |
| 191 | | //============================================================ |
| 192 | | // osd_thread_wait_free |
| 193 | | //============================================================ |
| 194 | | |
| 195 | | void osd_thread_wait_free(osd_thread *thread) |
| 196 | | { |
| 197 | | WaitForSingleObject(thread->handle, INFINITE); |
| 198 | | CloseHandle(thread->handle); |
| 199 | | free(thread); |
| 200 | | } |
| 201 | | |
| 202 | | //============================================================ |
| 203 | | // osd_thread_adjust_priority |
| 204 | | //============================================================ |
| 205 | | |
| 206 | | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 207 | | { |
| 208 | | if (adjust) |
| 209 | | SetThreadPriority(thread->handle, THREAD_PRIORITY_ABOVE_NORMAL); |
| 210 | | else |
| 211 | | SetThreadPriority(thread->handle, GetThreadPriority(GetCurrentThread())); |
| 212 | | return TRUE; |
| 213 | | } |
| 214 | | |
| 215 | | //============================================================ |
| 216 | | // osd_thread_cpu_affinity |
| 217 | | //============================================================ |
| 218 | | |
| 219 | | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 220 | | { |
| 221 | | return TRUE; |
| 222 | | } |
| 223 | | |
| 224 | | //============================================================ |
| 225 | | // osd_process_kill |
| 226 | | //============================================================ |
| 227 | | |
| 228 | | void osd_process_kill(void) |
| 229 | | { |
| 230 | | TerminateProcess(GetCurrentProcess(), -1); |
| 231 | | } |
| 12 | #include "../windows/winsync.c" |
| | No newline at end of file |
branches/osd/src/osd/windows/winwork.c
| r32170 | r32171 | |
| 19 | 19 | |
| 20 | 20 | // MAME headers |
| 21 | 21 | #include "osdcore.h" |
| 22 | |
| 23 | #include "winsync.h" |
| 24 | #include "winos.h" |
| 25 | |
| 22 | 26 | #include "eminline.h" |
| 23 | 27 | |
| 24 | 28 | |
| r32170 | r32171 | |
| 27 | 31 | //============================================================ |
| 28 | 32 | |
| 29 | 33 | #define KEEP_STATISTICS (0) |
| 30 | | #define USE_SCALABLE_LOCKS (0) |
| 31 | 34 | |
| 32 | | |
| 33 | | |
| 34 | 35 | //============================================================ |
| 35 | 36 | // PARAMETERS |
| 36 | 37 | //============================================================ |
| 37 | 38 | |
| 39 | #define ENV_PROCESSORS "OSDPROCESSORS" |
| 40 | #define ENV_WORKQUEUEMAXTHREADS "OSDWORKQUEUEMAXTHREADS" |
| 41 | |
| 38 | 42 | #define SPIN_LOOP_TIME (osd_ticks_per_second() / 1000) |
| 39 | 43 | |
| 40 | 44 | |
| r32170 | r32171 | |
| 59 | 63 | |
| 60 | 64 | #ifndef YieldProcessor |
| 61 | 65 | #ifdef __GNUC__ |
| 62 | | INLINE void YieldProcessor(void) |
| 66 | INLINE void osd_yield_processor(void) |
| 63 | 67 | { |
| 64 | 68 | __asm__ __volatile__ ( "rep; nop" ); |
| 65 | 69 | } |
| 66 | 70 | #else |
| 67 | | INLINE void YieldProcessor(void) |
| 71 | INLINE void osd_yield_processor(void) |
| 68 | 72 | { |
| 69 | 73 | __asm { rep nop } |
| 70 | 74 | } |
| 71 | 75 | #endif |
| 76 | #else |
| 77 | #define osd_yield_processor YieldProcessor |
| 72 | 78 | #endif |
| 73 | 79 | |
| 74 | 80 | |
| r32170 | r32171 | |
| 77 | 83 | // TYPE DEFINITIONS |
| 78 | 84 | //============================================================ |
| 79 | 85 | |
| 80 | | struct scalable_lock |
| 81 | | { |
| 82 | | #if USE_SCALABLE_LOCKS |
| 83 | | struct |
| 84 | | { |
| 85 | | volatile INT32 haslock; // do we have the lock? |
| 86 | | INT32 filler[64/4-1]; // assumes a 64-byte cache line |
| 87 | | } slot[WORK_MAX_THREADS]; // one slot per thread |
| 88 | | volatile INT32 nextindex; // index of next slot to use |
| 89 | | #else |
| 90 | | CRITICAL_SECTION section; |
| 91 | | #endif |
| 92 | | }; |
| 93 | | |
| 94 | | |
| 95 | 86 | struct work_thread_info |
| 96 | 87 | { |
| 97 | 88 | osd_work_queue * queue; // pointer back to the queue |
| 98 | | HANDLE handle; // handle to the thread |
| 99 | | HANDLE wakeevent; // wake event for the thread |
| 89 | osd_thread * handle; // handle to the thread |
| 90 | osd_event * wakeevent; // wake event for the thread |
| 100 | 91 | volatile INT32 active; // are we actively processing work? |
| 101 | 92 | |
| 102 | 93 | #if KEEP_STATISTICS |
| r32170 | r32171 | |
| 111 | 102 | |
| 112 | 103 | struct osd_work_queue |
| 113 | 104 | { |
| 114 | | scalable_lock lock; // lock for protecting the queue |
| 105 | osd_scalable_lock * lock; // lock for protecting the queue |
| 115 | 106 | osd_work_item * volatile list; // list of items in the queue |
| 116 | 107 | osd_work_item ** volatile tailptr; // pointer to the tail pointer of work items in the queue |
| 117 | 108 | osd_work_item * volatile free; // free list of work items |
| r32170 | r32171 | |
| 122 | 113 | UINT32 threads; // number of threads in this queue |
| 123 | 114 | UINT32 flags; // creation flags |
| 124 | 115 | work_thread_info * thread; // array of thread information |
| 125 | | HANDLE doneevent; // event signalled when work is complete |
| 116 | osd_event * doneevent; // event signalled when work is complete |
| 126 | 117 | |
| 127 | 118 | #if KEEP_STATISTICS |
| 128 | 119 | volatile INT32 itemsqueued; // total items queued |
| r32170 | r32171 | |
| 140 | 131 | osd_work_callback callback; // callback function |
| 141 | 132 | void * param; // callback parameter |
| 142 | 133 | void * result; // callback result |
| 143 | | HANDLE event; // event signalled when complete |
| 134 | osd_event * event; // event signalled when complete |
| 144 | 135 | UINT32 flags; // creation flags |
| 145 | 136 | volatile INT32 done; // is the item done? |
| 146 | 137 | }; |
| r32170 | r32171 | |
| 156 | 147 | //============================================================ |
| 157 | 148 | |
| 158 | 149 | static int effective_num_processors(void); |
| 159 | | static unsigned __stdcall worker_thread_entry(void *param); |
| 150 | static void * worker_thread_entry(void *param); |
| 160 | 151 | static void worker_thread_process(osd_work_queue *queue, work_thread_info *thread); |
| 161 | 152 | |
| 162 | 153 | |
| 163 | | |
| 164 | 154 | //============================================================ |
| 165 | | // Scalable Locks |
| 166 | | //============================================================ |
| 167 | | |
| 168 | | INLINE void scalable_lock_init(scalable_lock *lock) |
| 169 | | { |
| 170 | | memset(lock, 0, sizeof(*lock)); |
| 171 | | #if USE_SCALABLE_LOCKS |
| 172 | | lock->slot[0].haslock = TRUE; |
| 173 | | #else |
| 174 | | InitializeCriticalSection(&lock->section); |
| 175 | | #endif |
| 176 | | } |
| 177 | | |
| 178 | | |
| 179 | | INLINE INT32 scalable_lock_acquire(scalable_lock *lock) |
| 180 | | { |
| 181 | | #if USE_SCALABLE_LOCKS |
| 182 | | INT32 myslot = (atomic_increment32(&lock->nextindex) - 1) & (WORK_MAX_THREADS - 1); |
| 183 | | INT32 backoff = 1; |
| 184 | | |
| 185 | | while (!lock->slot[myslot].haslock) |
| 186 | | { |
| 187 | | INT32 backcount; |
| 188 | | for (backcount = 0; backcount < backoff; backcount++) |
| 189 | | YieldProcessor(); |
| 190 | | backoff <<= 1; |
| 191 | | } |
| 192 | | lock->slot[myslot].haslock = FALSE; |
| 193 | | return myslot; |
| 194 | | #else |
| 195 | | EnterCriticalSection(&lock->section); |
| 196 | | return 0; |
| 197 | | #endif |
| 198 | | } |
| 199 | | |
| 200 | | |
| 201 | | INLINE void scalable_lock_release(scalable_lock *lock, INT32 myslot) |
| 202 | | { |
| 203 | | #if USE_SCALABLE_LOCKS |
| 204 | | atomic_exchange32(&lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock, TRUE); |
| 205 | | #else |
| 206 | | LeaveCriticalSection(&lock->section); |
| 207 | | #endif |
| 208 | | } |
| 209 | | |
| 210 | | |
| 211 | | INLINE void scalable_lock_delete(scalable_lock *lock) |
| 212 | | { |
| 213 | | #if USE_SCALABLE_LOCKS |
| 214 | | #else |
| 215 | | DeleteCriticalSection(&lock->section); |
| 216 | | #endif |
| 217 | | } |
| 218 | | |
| 219 | | |
| 220 | | //============================================================ |
| 221 | 155 | // osd_work_queue_alloc |
| 222 | 156 | //============================================================ |
| 223 | 157 | |
| r32170 | r32171 | |
| 226 | 160 | int numprocs = effective_num_processors(); |
| 227 | 161 | osd_work_queue *queue; |
| 228 | 162 | int threadnum; |
| 229 | | TCHAR *osdworkqueuemaxthreads = _tgetenv(_T("OSDWORKQUEUEMAXTHREADS")); |
| 163 | char *osdworkqueuemaxthreads = osd_getenv("OSDWORKQUEUEMAXTHREADS"); |
| 230 | 164 | |
| 231 | 165 | // allocate a new queue |
| 232 | | queue = (osd_work_queue *)malloc(sizeof(*queue)); |
| 166 | queue = (osd_work_queue *)osd_malloc(sizeof(*queue)); |
| 233 | 167 | if (queue == NULL) |
| 234 | 168 | goto error; |
| 235 | 169 | memset(queue, 0, sizeof(*queue)); |
| r32170 | r32171 | |
| 239 | 173 | queue->flags = flags; |
| 240 | 174 | |
| 241 | 175 | // allocate events for the queue |
| 242 | | queue->doneevent = CreateEvent(NULL, TRUE, TRUE, NULL); // manual reset, signalled |
| 176 | queue->doneevent = osd_event_alloc(TRUE, TRUE); // manual reset, signalled |
| 243 | 177 | if (queue->doneevent == NULL) |
| 244 | 178 | goto error; |
| 245 | 179 | |
| 246 | 180 | // initialize the critical section |
| 247 | | scalable_lock_init(&queue->lock); |
| 181 | queue->lock = osd_scalable_lock_alloc(); |
| 182 | if (queue->lock == NULL) |
| 183 | goto error; |
| 248 | 184 | |
| 249 | 185 | // determine how many threads to create... |
| 250 | 186 | // on a single-CPU system, create 1 thread for I/O queues, and 0 threads for everything else |
| r32170 | r32171 | |
| 255 | 191 | else |
| 256 | 192 | queue->threads = (flags & WORK_QUEUE_FLAG_MULTI) ? numprocs : 1; |
| 257 | 193 | |
| 258 | | if (osdworkqueuemaxthreads != NULL && _stscanf(osdworkqueuemaxthreads, _T("%d"), &threadnum) == 1 && queue->threads > threadnum) |
| 194 | if (osdworkqueuemaxthreads != NULL && sscanf(osdworkqueuemaxthreads, "%d", &threadnum) == 1 && queue->threads > threadnum) |
| 259 | 195 | queue->threads = threadnum; |
| 260 | 196 | |
| 261 | 197 | // multi-queues with high frequency items should top out at 4 for now |
| r32170 | r32171 | |
| 267 | 203 | queue->threads = MIN(queue->threads, WORK_MAX_THREADS); |
| 268 | 204 | |
| 269 | 205 | // allocate memory for thread array (+1 to count the calling thread) |
| 270 | | queue->thread = (work_thread_info *)malloc((queue->threads + 1) * sizeof(queue->thread[0])); |
| 206 | queue->thread = (work_thread_info *)osd_malloc_array((queue->threads + 1) * sizeof(queue->thread[0])); |
| 271 | 207 | if (queue->thread == NULL) |
| 272 | 208 | goto error; |
| 273 | 209 | memset(queue->thread, 0, (queue->threads + 1) * sizeof(queue->thread[0])); |
| r32170 | r32171 | |
| 276 | 212 | for (threadnum = 0; threadnum < queue->threads; threadnum++) |
| 277 | 213 | { |
| 278 | 214 | work_thread_info *thread = &queue->thread[threadnum]; |
| 279 | | uintptr_t handle; |
| 280 | 215 | |
| 281 | 216 | // set a pointer back to the queue |
| 282 | 217 | thread->queue = queue; |
| 283 | 218 | |
| 284 | 219 | // create the per-thread wake event |
| 285 | | thread->wakeevent = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset, not signalled |
| 220 | thread->wakeevent = osd_event_alloc(FALSE, FALSE); // auto-reset, not signalled |
| 286 | 221 | if (thread->wakeevent == NULL) |
| 287 | 222 | goto error; |
| 288 | 223 | |
| 289 | 224 | // create the thread |
| 290 | | handle = _beginthreadex(NULL, 0, worker_thread_entry, thread, 0, NULL); |
| 291 | | thread->handle = (HANDLE)handle; |
| 225 | thread->handle = osd_thread_create(worker_thread_entry, thread); |
| 292 | 226 | if (thread->handle == NULL) |
| 293 | 227 | goto error; |
| 294 | 228 | |
| 295 | 229 | // set its priority: I/O threads get high priority because they are assumed to be |
| 296 | 230 | // blocked most of the time; other threads just match the creator's priority |
| 297 | 231 | if (flags & WORK_QUEUE_FLAG_IO) |
| 298 | | SetThreadPriority(thread->handle, THREAD_PRIORITY_ABOVE_NORMAL); |
| 232 | osd_thread_adjust_priority(thread->handle, 1); |
| 299 | 233 | else |
| 300 | | SetThreadPriority(thread->handle, GetThreadPriority(GetCurrentThread())); |
| 234 | osd_thread_adjust_priority(thread->handle, 0); |
| 301 | 235 | } |
| 302 | 236 | |
| 303 | 237 | // start a timer going for "waittime" on the main thread |
| r32170 | r32171 | |
| 339 | 273 | if (queue->flags & WORK_QUEUE_FLAG_MULTI) |
| 340 | 274 | { |
| 341 | 275 | work_thread_info *thread = &queue->thread[queue->threads]; |
| 342 | | osd_ticks_t stopspin = osd_ticks() + timeout; |
| 343 | 276 | |
| 344 | 277 | end_timing(thread->waittime); |
| 345 | 278 | |
| r32170 | r32171 | |
| 349 | 282 | // if we're a high frequency queue, spin until done |
| 350 | 283 | if (queue->flags & WORK_QUEUE_FLAG_HIGH_FREQ) |
| 351 | 284 | { |
| 285 | osd_ticks_t stopspin = osd_ticks() + timeout; |
| 286 | |
| 352 | 287 | // spin until we're done |
| 353 | 288 | begin_timing(thread->spintime); |
| 354 | 289 | while (queue->items != 0 && osd_ticks() < stopspin) |
| 355 | | YieldProcessor(); |
| 290 | osd_yield_processor(); |
| 356 | 291 | end_timing(thread->spintime); |
| 357 | 292 | |
| 358 | 293 | begin_timing(thread->waittime); |
| r32170 | r32171 | |
| 362 | 297 | } |
| 363 | 298 | |
| 364 | 299 | // reset our done event and double-check the items before waiting |
| 365 | | ResetEvent(queue->doneevent); |
| 300 | osd_event_reset(queue->doneevent); |
| 366 | 301 | atomic_exchange32(&queue->waiting, TRUE); |
| 367 | 302 | if (queue->items != 0) |
| 368 | | WaitForSingleObject(queue->doneevent, timeout * 1000 / osd_ticks_per_second()); |
| 303 | osd_event_wait(queue->doneevent, timeout); |
| 369 | 304 | atomic_exchange32(&queue->waiting, FALSE); |
| 370 | 305 | |
| 371 | 306 | // return TRUE if we actually hit 0 |
| r32170 | r32171 | |
| 393 | 328 | { |
| 394 | 329 | work_thread_info *thread = &queue->thread[threadnum]; |
| 395 | 330 | if (thread->wakeevent != NULL) |
| 396 | | SetEvent(thread->wakeevent); |
| 331 | osd_event_set(thread->wakeevent); |
| 397 | 332 | } |
| 398 | 333 | |
| 399 | 334 | // wait for all the threads to go away |
| r32170 | r32171 | |
| 404 | 339 | // block on the thread going away, then close the handle |
| 405 | 340 | if (thread->handle != NULL) |
| 406 | 341 | { |
| 407 | | WaitForSingleObject(thread->handle, INFINITE); |
| 408 | | CloseHandle(thread->handle); |
| 342 | osd_thread_wait_free(thread->handle); |
| 409 | 343 | } |
| 410 | 344 | |
| 411 | 345 | // clean up the wake event |
| 412 | 346 | if (thread->wakeevent != NULL) |
| 413 | | CloseHandle(thread->wakeevent); |
| 347 | osd_event_free(thread->wakeevent); |
| 414 | 348 | } |
| 415 | 349 | |
| 416 | 350 | #if KEEP_STATISTICS |
| r32170 | r32171 | |
| 419 | 353 | { |
| 420 | 354 | work_thread_info *thread = &queue->thread[threadnum]; |
| 421 | 355 | osd_ticks_t total = thread->runtime + thread->waittime + thread->spintime; |
| 422 | | printf("Thread %d: items=%9d run=%5.2f%% (%5.2f%%) spin=%5.2f%% wait/other=%5.2f%%\n", |
| 356 | printf("Thread %d: items=%9d run=%5.2f%% (%5.2f%%) spin=%5.2f%% wait/other=%5.2f%% total=%9d\n", |
| 423 | 357 | threadnum, thread->itemsdone, |
| 424 | 358 | (double)thread->runtime * 100.0 / (double)total, |
| 425 | 359 | (double)thread->actruntime * 100.0 / (double)total, |
| 426 | 360 | (double)thread->spintime * 100.0 / (double)total, |
| 427 | | (double)thread->waittime * 100.0 / (double)total); |
| 361 | (double)thread->waittime * 100.0 / (double)total, |
| 362 | (UINT32) total); |
| 428 | 363 | } |
| 429 | 364 | #endif |
| 430 | 365 | } |
| 431 | 366 | |
| 432 | 367 | // free the list |
| 433 | 368 | if (queue->thread != NULL) |
| 434 | | free(queue->thread); |
| 369 | osd_free(queue->thread); |
| 435 | 370 | |
| 436 | | scalable_lock_delete(&queue->lock); |
| 437 | | |
| 438 | 371 | // free all the events |
| 439 | 372 | if (queue->doneevent != NULL) |
| 440 | | CloseHandle(queue->doneevent); |
| 373 | osd_event_free(queue->doneevent); |
| 441 | 374 | |
| 442 | 375 | // free all items in the free list |
| 443 | 376 | while (queue->free != NULL) |
| r32170 | r32171 | |
| 445 | 378 | osd_work_item *item = (osd_work_item *)queue->free; |
| 446 | 379 | queue->free = item->next; |
| 447 | 380 | if (item->event != NULL) |
| 448 | | CloseHandle(item->event); |
| 449 | | free(item); |
| 381 | osd_event_free(item->event); |
| 382 | osd_free(item); |
| 450 | 383 | } |
| 451 | 384 | |
| 452 | 385 | // free all items in the active list |
| r32170 | r32171 | |
| 455 | 388 | osd_work_item *item = (osd_work_item *)queue->list; |
| 456 | 389 | queue->list = item->next; |
| 457 | 390 | if (item->event != NULL) |
| 458 | | CloseHandle(item->event); |
| 459 | | free(item); |
| 391 | osd_event_free(item->event); |
| 392 | osd_free(item); |
| 460 | 393 | } |
| 461 | 394 | |
| 462 | 395 | #if KEEP_STATISTICS |
| r32170 | r32171 | |
| 466 | 399 | printf("Spin loops = %9d\n", queue->spinloops); |
| 467 | 400 | #endif |
| 468 | 401 | |
| 402 | osd_scalable_lock_free(queue->lock); |
| 469 | 403 | // free the queue itself |
| 470 | | free(queue); |
| 404 | osd_free(queue); |
| 471 | 405 | } |
| 472 | 406 | |
| 473 | 407 | |
| r32170 | r32171 | |
| 497 | 431 | if (item == NULL) |
| 498 | 432 | { |
| 499 | 433 | // allocate the item |
| 500 | | item = (osd_work_item *)malloc(sizeof(*item)); |
| 434 | item = (osd_work_item *)osd_malloc(sizeof(*item)); |
| 501 | 435 | if (item == NULL) |
| 502 | 436 | return NULL; |
| 503 | 437 | item->event = NULL; |
| r32170 | r32171 | |
| 520 | 454 | } |
| 521 | 455 | |
| 522 | 456 | // enqueue the whole thing within the critical section |
| 523 | | lockslot = scalable_lock_acquire(&queue->lock); |
| 457 | lockslot = osd_scalable_lock_acquire(queue->lock); |
| 524 | 458 | *queue->tailptr = itemlist; |
| 525 | 459 | queue->tailptr = item_tailptr; |
| 526 | | scalable_lock_release(&queue->lock, lockslot); |
| 460 | osd_scalable_lock_release(queue->lock, lockslot); |
| 527 | 461 | |
| 528 | 462 | // increment the number of items in the queue |
| 529 | 463 | atomic_add32(&queue->items, numitems); |
| r32170 | r32171 | |
| 542 | 476 | // if this thread is not active, wake him up |
| 543 | 477 | if (!thread->active) |
| 544 | 478 | { |
| 545 | | SetEvent(thread->wakeevent); |
| 479 | osd_event_set(thread->wakeevent); |
| 546 | 480 | add_to_stat(&queue->setevents, 1); |
| 547 | 481 | |
| 548 | 482 | // for non-shared, the first one we find is good enough |
| r32170 | r32171 | |
| 573 | 507 | |
| 574 | 508 | // if we don't have an event, create one |
| 575 | 509 | if (item->event == NULL) |
| 576 | | item->event = CreateEvent(NULL, TRUE, FALSE, NULL); // manual reset, not signalled |
| 510 | item->event = osd_event_alloc(TRUE, FALSE); // manual reset, not signalled |
| 577 | 511 | else |
| 578 | | ResetEvent(item->event); |
| 512 | osd_event_reset(item->event); |
| 579 | 513 | |
| 580 | 514 | // if we don't have an event, we need to spin (shouldn't ever really happen) |
| 581 | 515 | if (item->event == NULL) |
| 582 | 516 | { |
| 583 | 517 | osd_ticks_t stopspin = osd_ticks() + timeout; |
| 584 | 518 | while (!item->done && osd_ticks() < stopspin) |
| 585 | | YieldProcessor(); |
| 519 | osd_yield_processor(); |
| 586 | 520 | } |
| 587 | 521 | |
| 588 | 522 | // otherwise, block on the event until done |
| 589 | 523 | else if (!item->done) |
| 590 | | WaitForSingleObject(item->event, timeout * 1000 / osd_ticks_per_second()); |
| 524 | osd_event_wait(item->event, timeout); |
| 591 | 525 | |
| 592 | 526 | // return TRUE if the refcount actually hit 0 |
| 593 | 527 | return item->done; |
| r32170 | r32171 | |
| 630 | 564 | |
| 631 | 565 | static int effective_num_processors(void) |
| 632 | 566 | { |
| 633 | | SYSTEM_INFO info; |
| 634 | | // fetch the info from the system |
| 635 | | GetSystemInfo(&info); |
| 567 | int physprocs = osd_get_num_processors(); |
| 636 | 568 | |
| 569 | // osd_num_processors == 0 for 'auto' |
| 637 | 570 | if (osd_num_processors > 0) |
| 638 | 571 | { |
| 639 | | return MIN(info.dwNumberOfProcessors * 4, osd_num_processors); |
| 572 | return MIN(4 * physprocs, osd_num_processors); |
| 640 | 573 | } |
| 641 | 574 | else |
| 642 | 575 | { |
| 643 | | TCHAR *procsoverride; |
| 576 | char *procsoverride; |
| 644 | 577 | int numprocs = 0; |
| 645 | 578 | |
| 646 | 579 | // if the OSDPROCESSORS environment variable is set, use that value if valid |
| 647 | 580 | // note that we permit more than the real number of processors for testing |
| 648 | | procsoverride = _tgetenv(_T("OSDPROCESSORS")); |
| 649 | | if (procsoverride != NULL && _stscanf(procsoverride, _T("%d"), &numprocs) == 1 && numprocs > 0) |
| 650 | | return MIN(info.dwNumberOfProcessors * 4, numprocs); |
| 581 | procsoverride = osd_getenv(ENV_PROCESSORS); |
| 582 | if (procsoverride != NULL && sscanf(procsoverride, "%d", &numprocs) == 1 && numprocs > 0) |
| 583 | return MIN(4 * physprocs, numprocs); |
| 651 | 584 | |
| 652 | | return info.dwNumberOfProcessors; |
| 585 | // otherwise, return the info from the system |
| 586 | return physprocs; |
| 653 | 587 | } |
| 654 | 588 | } |
| 655 | 589 | |
| r32170 | r32171 | |
| 658 | 592 | // worker_thread_entry |
| 659 | 593 | //============================================================ |
| 660 | 594 | |
| 661 | | static unsigned __stdcall worker_thread_entry(void *param) |
| 595 | static void *worker_thread_entry(void *param) |
| 662 | 596 | { |
| 663 | 597 | work_thread_info *thread = (work_thread_info *)param; |
| 664 | 598 | osd_work_queue *queue = thread->queue; |
| r32170 | r32171 | |
| 666 | 600 | // loop until we exit |
| 667 | 601 | for ( ;; ) |
| 668 | 602 | { |
| 603 | // block waiting for work or exit |
| 669 | 604 | // bail on exit, and only wait if there are no pending items in queue |
| 670 | 605 | if (!queue->exiting && queue->list == NULL) |
| 671 | 606 | { |
| 672 | 607 | begin_timing(thread->waittime); |
| 673 | | WaitForSingleObject(thread->wakeevent, INFINITE); |
| 608 | osd_event_wait(thread->wakeevent, INFINITE); |
| 674 | 609 | end_timing(thread->waittime); |
| 675 | 610 | } |
| 676 | 611 | if (queue->exiting) |
| r32170 | r32171 | |
| 695 | 630 | begin_timing(thread->spintime); |
| 696 | 631 | stopspin = osd_ticks() + SPIN_LOOP_TIME; |
| 697 | 632 | while (queue->list == NULL && osd_ticks() < stopspin) |
| 698 | | YieldProcessor(); |
| 633 | osd_yield_processor(); |
| 699 | 634 | end_timing(thread->spintime); |
| 700 | 635 | } |
| 701 | 636 | |
| r32170 | r32171 | |
| 709 | 644 | atomic_exchange32(&thread->active, FALSE); |
| 710 | 645 | atomic_decrement32(&queue->livethreads); |
| 711 | 646 | } |
| 712 | | return 0; |
| 647 | return NULL; |
| 713 | 648 | } |
| 714 | 649 | |
| 715 | 650 | |
| r32170 | r32171 | |
| 730 | 665 | INT32 lockslot; |
| 731 | 666 | |
| 732 | 667 | // use a critical section to synchronize the removal of items |
| 733 | | lockslot = scalable_lock_acquire(&queue->lock); |
| 668 | lockslot = osd_scalable_lock_acquire(queue->lock); |
| 734 | 669 | { |
| 735 | 670 | // pull the item from the queue |
| 736 | 671 | item = (osd_work_item *)queue->list; |
| r32170 | r32171 | |
| 741 | 676 | queue->tailptr = (osd_work_item **)&queue->list; |
| 742 | 677 | } |
| 743 | 678 | } |
| 744 | | scalable_lock_release(&queue->lock, lockslot); |
| 679 | osd_scalable_lock_release(queue->lock, lockslot); |
| 745 | 680 | |
| 746 | 681 | // process non-NULL items |
| 747 | 682 | if (item != NULL) |
| r32170 | r32171 | |
| 763 | 698 | // set the result and signal the event |
| 764 | 699 | else if (item->event != NULL) |
| 765 | 700 | { |
| 766 | | SetEvent(item->event); |
| 701 | osd_event_set(item->event); |
| 767 | 702 | add_to_stat(&item->queue->setevents, 1); |
| 768 | 703 | } |
| 769 | 704 | |
| r32170 | r32171 | |
| 776 | 711 | // we don't need to set the doneevent for multi queues because they spin |
| 777 | 712 | if (queue->waiting) |
| 778 | 713 | { |
| 779 | | SetEvent(queue->doneevent); |
| 714 | osd_event_set(queue->doneevent); |
| 780 | 715 | add_to_stat(&queue->setevents, 1); |
| 781 | 716 | } |
| 782 | 717 | |
branches/osd/src/osd/windows/winsync.c
| r32170 | r32171 | |
| 10 | 10 | #define WIN32_LEAN_AND_MEAN |
| 11 | 11 | #include <windows.h> |
| 12 | 12 | #include <stdlib.h> |
| 13 | #include <process.h> |
| 13 | 14 | |
| 14 | 15 | // MAME headers |
| 15 | 16 | #include "osdcore.h" |
| 16 | 17 | #include "osinline.h" |
| 18 | #include "winsync.h" |
| 17 | 19 | |
| 18 | 20 | |
| 19 | 21 | //============================================================ |
| r32170 | r32171 | |
| 21 | 23 | //============================================================ |
| 22 | 24 | |
| 23 | 25 | #define DEBUG_SLOW_LOCKS 0 |
| 26 | #define USE_SCALABLE_LOCKS (0) |
| 24 | 27 | |
| 25 | 28 | |
| 26 | 29 | |
| r32170 | r32171 | |
| 35 | 38 | CRITICAL_SECTION critsect; |
| 36 | 39 | }; |
| 37 | 40 | |
| 41 | struct osd_event |
| 42 | { |
| 43 | void * ptr; |
| 44 | }; |
| 38 | 45 | |
| 46 | struct osd_thread { |
| 47 | HANDLE handle; |
| 48 | osd_thread_callback callback; |
| 49 | void *param; |
| 50 | }; |
| 39 | 51 | |
| 52 | struct osd_scalable_lock |
| 53 | { |
| 54 | #if USE_SCALABLE_LOCKS |
| 55 | struct |
| 56 | { |
| 57 | volatile INT32 haslock; // do we have the lock? |
| 58 | INT32 filler[64/4-1]; // assumes a 64-byte cache line |
| 59 | } slot[WORK_MAX_THREADS]; // one slot per thread |
| 60 | volatile INT32 nextindex; // index of next slot to use |
| 61 | #else |
| 62 | CRITICAL_SECTION section; |
| 63 | #endif |
| 64 | }; |
| 65 | |
| 66 | |
| 40 | 67 | //============================================================ |
| 41 | 68 | // GLOBAL VARIABLES |
| 42 | 69 | //============================================================ |
| r32170 | r32171 | |
| 169 | 196 | { |
| 170 | 197 | return InterlockedExchangeAdd((LONG *) ptr, delta) + delta; |
| 171 | 198 | } |
| 199 | |
| 200 | //============================================================ |
| 201 | // osd_event_alloc |
| 202 | //============================================================ |
| 203 | |
| 204 | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 205 | { |
| 206 | return (osd_event *) CreateEvent(NULL, manualreset, initialstate, NULL); |
| 207 | } |
| 208 | |
| 209 | //============================================================ |
| 210 | // osd_event_free |
| 211 | //============================================================ |
| 212 | |
| 213 | void osd_event_free(osd_event *event) |
| 214 | { |
| 215 | CloseHandle((HANDLE) event); |
| 216 | } |
| 217 | |
| 218 | //============================================================ |
| 219 | // osd_event_set |
| 220 | //============================================================ |
| 221 | |
| 222 | void osd_event_set(osd_event *event) |
| 223 | { |
| 224 | SetEvent((HANDLE) event); |
| 225 | } |
| 226 | |
| 227 | //============================================================ |
| 228 | // osd_event_reset |
| 229 | //============================================================ |
| 230 | |
| 231 | void osd_event_reset(osd_event *event) |
| 232 | { |
| 233 | ResetEvent((HANDLE) event); |
| 234 | } |
| 235 | |
| 236 | //============================================================ |
| 237 | // osd_event_wait |
| 238 | //============================================================ |
| 239 | |
| 240 | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 241 | { |
| 242 | int ret = WaitForSingleObject((HANDLE) event, timeout * 1000 / osd_ticks_per_second()); |
| 243 | return ( ret == WAIT_OBJECT_0); |
| 244 | } |
| 245 | |
| 246 | //============================================================ |
| 247 | // osd_thread_create |
| 248 | //============================================================ |
| 249 | |
| 250 | static unsigned __stdcall worker_thread_entry(void *param) |
| 251 | { |
| 252 | osd_thread *thread = (osd_thread *) param; |
| 253 | void *res; |
| 254 | res = thread->callback(thread->param); |
| 255 | #ifdef PTR64 |
| 256 | return (unsigned) (long long) res; |
| 257 | #else |
| 258 | return (unsigned) res; |
| 259 | #endif |
| 260 | } |
| 261 | |
| 262 | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 263 | { |
| 264 | osd_thread *thread; |
| 265 | uintptr_t handle; |
| 266 | |
| 267 | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 268 | thread->callback = callback; |
| 269 | thread->param = cbparam; |
| 270 | handle = _beginthreadex(NULL, 0, worker_thread_entry, thread, 0, NULL); |
| 271 | thread->handle = (HANDLE) handle; |
| 272 | return thread; |
| 273 | } |
| 274 | |
| 275 | //============================================================ |
| 276 | // osd_thread_wait_free |
| 277 | //============================================================ |
| 278 | |
| 279 | void osd_thread_wait_free(osd_thread *thread) |
| 280 | { |
| 281 | WaitForSingleObject(thread->handle, INFINITE); |
| 282 | CloseHandle(thread->handle); |
| 283 | free(thread); |
| 284 | } |
| 285 | |
| 286 | //============================================================ |
| 287 | // osd_thread_adjust_priority |
| 288 | //============================================================ |
| 289 | |
| 290 | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 291 | { |
| 292 | if (adjust) |
| 293 | SetThreadPriority(thread->handle, THREAD_PRIORITY_ABOVE_NORMAL); |
| 294 | else |
| 295 | SetThreadPriority(thread->handle, GetThreadPriority(GetCurrentThread())); |
| 296 | return TRUE; |
| 297 | } |
| 298 | |
| 299 | //============================================================ |
| 300 | // osd_thread_cpu_affinity |
| 301 | //============================================================ |
| 302 | |
| 303 | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 304 | { |
| 305 | return TRUE; |
| 306 | } |
| 307 | |
| 308 | //============================================================ |
| 309 | // osd_process_kill |
| 310 | //============================================================ |
| 311 | |
| 312 | void osd_process_kill(void) |
| 313 | { |
| 314 | TerminateProcess(GetCurrentProcess(), -1); |
| 315 | } |
| 316 | |
| 317 | //============================================================ |
| 318 | // Scalable Locks |
| 319 | //============================================================ |
| 320 | |
| 321 | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 322 | { |
| 323 | osd_scalable_lock *lock; |
| 324 | |
| 325 | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 326 | |
| 327 | memset(lock, 0, sizeof(*lock)); |
| 328 | #if USE_SCALABLE_LOCKS |
| 329 | lock->slot[0].haslock = TRUE; |
| 330 | #else |
| 331 | InitializeCriticalSection(&lock->section); |
| 332 | #endif |
| 333 | return lock; |
| 334 | } |
| 335 | |
| 336 | |
| 337 | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 338 | { |
| 339 | #if USE_SCALABLE_LOCKS |
| 340 | INT32 myslot = (atomic_increment32(&lock->nextindex) - 1) & (WORK_MAX_THREADS - 1); |
| 341 | INT32 backoff = 1; |
| 342 | |
| 343 | while (!lock->slot[myslot].haslock) |
| 344 | { |
| 345 | INT32 backcount; |
| 346 | for (backcount = 0; backcount < backoff; backcount++) |
| 347 | osd_yield_processor(); |
| 348 | backoff <<= 1; |
| 349 | } |
| 350 | lock->slot[myslot].haslock = FALSE; |
| 351 | return myslot; |
| 352 | #else |
| 353 | EnterCriticalSection(&lock->section); |
| 354 | return 0; |
| 355 | #endif |
| 356 | } |
| 357 | |
| 358 | |
| 359 | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 360 | { |
| 361 | #if USE_SCALABLE_LOCKS |
| 362 | atomic_exchange32(&lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock, TRUE); |
| 363 | #else |
| 364 | LeaveCriticalSection(&lock->section); |
| 365 | #endif |
| 366 | } |
| 367 | |
| 368 | |
| 369 | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 370 | { |
| 371 | #if USE_SCALABLE_LOCKS |
| 372 | #else |
| 373 | DeleteCriticalSection(&lock->section); |
| 374 | #endif |
| 375 | free(lock); |
| 376 | } |
| | No newline at end of file |
branches/osd/src/osd/windows/winsync.h
| r0 | r32171 | |
| 1 | //============================================================ |
| 2 | // |
| 3 | // winsync.h - Windows core synchronization functions |
| 4 | // |
| 5 | // Copyright (c) 1996-2014, Nicola Salmoria and the MAME Team. |
| 6 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | // |
| 8 | //============================================================ |
| 9 | |
| 10 | #ifndef __WINSYNC__ |
| 11 | #define __WINSYNC__ |
| 12 | |
| 13 | /*************************************************************************** |
| 14 | SYNCHRONIZATION INTERFACES - Events |
| 15 | ***************************************************************************/ |
| 16 | |
| 17 | /* osd_event is an opaque type which represents a setable/resetable event */ |
| 18 | |
| 19 | struct osd_event; |
| 20 | |
| 21 | |
| 22 | /*----------------------------------------------------------------------------- |
| 23 | osd_lock_event_alloc: allocate a new event |
| 24 | |
| 25 | Parameters: |
| 26 | |
| 27 | manualreset - boolean. If true, the event will be automatically set |
| 28 | to non-signalled after a thread successfully waited for |
| 29 | it. |
| 30 | initialstate - boolean. If true, the event is signalled initially. |
| 31 | |
| 32 | Return value: |
| 33 | |
| 34 | A pointer to the allocated event. |
| 35 | -----------------------------------------------------------------------------*/ |
| 36 | osd_event *osd_event_alloc(int manualreset, int initialstate); |
| 37 | |
| 38 | |
| 39 | /*----------------------------------------------------------------------------- |
| 40 | osd_event_wait: wait for an event to be signalled |
| 41 | |
| 42 | Parameters: |
| 43 | |
| 44 | event - The event to wait for. If the event is in signalled state, the |
| 45 | function returns immediately. If not it will wait for the event |
| 46 | to become signalled. |
| 47 | timeout - timeout in osd_ticks |
| 48 | |
| 49 | Return value: |
| 50 | |
| 51 | TRUE: The event was signalled |
| 52 | FALSE: A timeout occurred |
| 53 | -----------------------------------------------------------------------------*/ |
| 54 | int osd_event_wait(osd_event *event, osd_ticks_t timeout); |
| 55 | |
| 56 | |
| 57 | /*----------------------------------------------------------------------------- |
| 58 | osd_event_reset: reset an event to non-signalled state |
| 59 | |
| 60 | Parameters: |
| 61 | |
| 62 | event - The event to set to non-signalled state |
| 63 | |
| 64 | Return value: |
| 65 | |
| 66 | None |
| 67 | -----------------------------------------------------------------------------*/ |
| 68 | void osd_event_reset(osd_event *event); |
| 69 | |
| 70 | |
| 71 | /*----------------------------------------------------------------------------- |
| 72 | osd_event_set: set an event to signalled state |
| 73 | |
| 74 | Parameters: |
| 75 | |
| 76 | event - The event to set to signalled state |
| 77 | |
| 78 | Return value: |
| 79 | |
| 80 | None |
| 81 | |
| 82 | Notes: |
| 83 | |
| 84 | All threads waiting for the event will be signalled. |
| 85 | -----------------------------------------------------------------------------*/ |
| 86 | void osd_event_set(osd_event *event); |
| 87 | |
| 88 | |
| 89 | /*----------------------------------------------------------------------------- |
| 90 | osd_event_free: free the memory and resources associated with an osd_event |
| 91 | |
| 92 | Parameters: |
| 93 | |
| 94 | event - a pointer to a previously allocated osd_event. |
| 95 | |
| 96 | Return value: |
| 97 | |
| 98 | None. |
| 99 | -----------------------------------------------------------------------------*/ |
| 100 | void osd_event_free(osd_event *event); |
| 101 | |
| 102 | /*************************************************************************** |
| 103 | SYNCHRONIZATION INTERFACES - Threads |
| 104 | ***************************************************************************/ |
| 105 | |
| 106 | /* osd_thread is an opaque type which represents a thread */ |
| 107 | struct osd_thread; |
| 108 | |
| 109 | |
| 110 | /* osd_thread_callback is a callback function that will be called from the thread */ |
| 111 | typedef void *(*osd_thread_callback)(void *param); |
| 112 | |
| 113 | |
| 114 | /*----------------------------------------------------------------------------- |
| 115 | osd_thread_create: create a new thread |
| 116 | |
| 117 | Parameters: |
| 118 | |
| 119 | callback - The callback function to be called once the thread is up |
| 120 | cbparam - The parameter to pass to the callback function. |
| 121 | |
| 122 | Return value: |
| 123 | |
| 124 | A pointer to the created thread. |
| 125 | -----------------------------------------------------------------------------*/ |
| 126 | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam); |
| 127 | |
| 128 | /*----------------------------------------------------------------------------- |
| 129 | osd_thread_adjust_priority: adjust priority of a thread |
| 130 | |
| 131 | Parameters: |
| 132 | |
| 133 | thread - A pointer to a previously created thread. |
| 134 | adjust - signed integer to add to the thread priority |
| 135 | |
| 136 | Return value: |
| 137 | |
| 138 | TRUE on success, FALSE on failure |
| 139 | -----------------------------------------------------------------------------*/ |
| 140 | int osd_thread_adjust_priority(osd_thread *thread, int adjust); |
| 141 | |
| 142 | |
| 143 | /*----------------------------------------------------------------------------- |
| 144 | osd_thread_cpu_affinity: change cpu affinity of a thread |
| 145 | |
| 146 | Parameters: |
| 147 | |
| 148 | thread - A pointer to a previously created thread |
| 149 | or NULL for main thread |
| 150 | mask - bitmask to which cpus to bind |
| 151 | i.e. 0x01 1st cpu, 0x02, 2nd cpu, 0x04 3rd cpu |
| 152 | |
| 153 | Return value: |
| 154 | |
| 155 | TRUE on success, FALSE on failure |
| 156 | -----------------------------------------------------------------------------*/ |
| 157 | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask); |
| 158 | |
| 159 | |
| 160 | /*----------------------------------------------------------------------------- |
| 161 | osd_thread_wait_free: wait for thread to finish and free resources |
| 162 | |
| 163 | Parameters: |
| 164 | |
| 165 | thread - A pointer to a previously created thread. |
| 166 | |
| 167 | Return value: |
| 168 | |
| 169 | None. |
| 170 | -----------------------------------------------------------------------------*/ |
| 171 | void osd_thread_wait_free(osd_thread *thread); |
| 172 | |
| 173 | /*----------------------------------------------------------------------------- |
| 174 | osd_process_kill: kill the current process |
| 175 | |
| 176 | Parameters: |
| 177 | |
| 178 | None. |
| 179 | |
| 180 | Return value: |
| 181 | |
| 182 | None. |
| 183 | -----------------------------------------------------------------------------*/ |
| 184 | void osd_process_kill(void); |
| 185 | |
| 186 | //============================================================ |
| 187 | // Scalable Locks |
| 188 | //============================================================ |
| 189 | |
| 190 | struct osd_scalable_lock; |
| 191 | |
| 192 | osd_scalable_lock *osd_scalable_lock_alloc(void); |
| 193 | |
| 194 | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock); |
| 195 | |
| 196 | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot); |
| 197 | |
| 198 | void osd_scalable_lock_free(osd_scalable_lock *lock); |
| 199 | |
| 200 | #endif /* __WINSYNC__ */ |
| | No newline at end of file |