int main() { Barrier barrier1(3); Barrier barrier2(3); arrived_all = false; processed_all = true; arrived_count.store(0); processed_count.store(allowed_max); std::thread worker[50]; for (int i = 0; i < 6; i++) worker[i] = std::thread(worker_thread, i, &barrier1, &barrier2); { std::lock_guard<std::mutex> lk(m); std::cout << "Back in main(), after initialing first thread batch " << data << std::endl; } // wait until worker dies finishes execution for (int i = 0; i < 6; i++) worker[i].join(); // for (int i = 5; i < 10; i++) // worker[i] = std::thread(worker_thread, i); // { // std::lock_guard<std::mutex> lk(m); // std::cout << "Back in main(), after initialing second thread batch." << std::endl; // } // // wait until worker dies finishes execution // for (int i = 5; i < 10; i++) // worker[i].join(); std::cout << "finished main(), data = " << data << std::endl; }
void spring_time::sleep(bool forceThreadSleep) { if (forceThreadSleep) { spring::this_thread::sleep_for(chrono::nanoseconds(toNanoSecsi())); return; } // for very short time intervals use a yielding loop (yield is ~5x more accurate than sleep(), check the UnitTest) if (toMicroSecsi() < (avgThreadSleepTimeMicroSecs + avgThreadYieldTimeMicroSecs * 5)) { const spring_time s = gettime(); while ((gettime() - s) < *this) thread_yield(); return; } // expected wakeup time const spring_time t0 = gettime() + *this; spring::this_thread::sleep_for(chrono::nanoseconds(toNanoSecsi())); const spring_time t1 = gettime(); const spring_time dt = t1 - t0; if (t1 >= t0) { // yes, it's not 100% thread correct, but it's okay when 1 of 1 million writes is dropped int avg = avgThreadSleepTimeMicroSecs.load(); int newAvg = mix<float>(avg, dt.toMicroSecsf(), 0.1f); avgThreadSleepTimeMicroSecs.store(newAvg); } }
inline bool update() { if (windowId.load() == s_currentNativeWindowId.load()) return false; s_currentNativeWindowMutex.lock(); window = s_currentNativeWindow; windowId.store(s_currentNativeWindowId.load()); s_currentNativeWindowMutex.unlock(); return true; }
void stepLeft() { std::unique_lock<std::mutex> lock(mutex); for (int i = 0; i < 10; ++i) { std::cout << "left" << std::endl; isWaiting.fetch_add(1); if (isWaiting.load() % 2 != 0) { condVar.notify_one(); } else { condVar.wait(lock); } } }
static void thread_yield() { const spring_time t0 = spring_time::gettime(); this_thread::yield(); const spring_time t1 = spring_time::gettime(); const spring_time dt = t1 - t0; if (t1 >= t0) { // yes, it's not 100% thread correct, but it's okay when 1 of 1 million writes is dropped int avg = avgThreadYieldTimeMicroSecs.load(); int newAvg = mix<float>(avg, dt.toMicroSecsf(), 0.1f); avgThreadYieldTimeMicroSecs.store(newAvg); } }
TEST(JobSystem, JobSystemParallelChildren) { v = 0; JobSystem js; js.adopt(); struct User { std::atomic_int calls = {0}; void func(JobSystem&, JobSystem::Job*) { v++; calls++; }; } j; JobSystem::Job* root = js.createJob<User, &User::func>(nullptr, &j); for (int i=0 ; i<256 ; i++) { JobSystem::Job* job = js.createJob<User, &User::func>(root, &j); js.run(job); } js.runAndWait(root); EXPECT_EQ(257, v.load()); EXPECT_EQ(257, j.calls); js.emancipate(); }
void HAL_CleanNotifier(HAL_NotifierHandle notifierHandle, int32_t* status) { { std::lock_guard<priority_recursive_mutex> sync(notifierMutex); auto notifier = notifierHandles.Get(notifierHandle); if (!notifier) return; // remove from list if (notifier->prev) notifier->prev->next = notifier->next; if (notifier->next) notifier->next->prev = notifier->prev; if (notifiers == notifier) notifiers = notifier->next; notifierHandles.Free(notifierHandle); if (notifier->threaded) { NotifierThreadOwner* owner = static_cast<NotifierThreadOwner*>(notifier->param); delete owner; } } if (notifierRefCount.fetch_sub(1) == 1) { std::lock_guard<priority_mutex> sync(notifierInterruptMutex); // if this was the last notifier, clean up alarm and manager if (notifierAlarm) { notifierAlarm->writeEnable(false, status); notifierAlarm = nullptr; } if (notifierManager) { notifierManager->disable(status); notifierManager = nullptr; } closestTrigger = UINT64_MAX; } }
static void onSurfaceDestroyed(JNIEnv */*env*/, jobject /*object*/) { s_currentNativeWindowMutex.lock(); s_currentNativeWindow.reset(); s_currentNativeWindowId.store(0); s_currentNativeWindowMutex.unlock(); }
Texture TextureBuilder::Build2DTexture(TextureBindpoint target, unsigned width, unsigned height, unsigned count, unsigned channels, TexturePixelFormat pixelFormat, bool useMipmaps) { int current_id = id.fetch_add(1, std::memory_order_relaxed); Texture result; result.info.width = width; result.info.height = height; result.info.count = count; result.info.type = TextureType::Tex2D; result.info.target = target; result.info.targetPixelFormat = pixelFormat; result.info.channels = channels; result.info.name = std::string(NAME_PREFIX) + std::to_string(current_id); unsigned minSize = std::min(width, height); if (useMipmaps) { unsigned i = 0; while (minSize > 1) { minSize /= 2; i++; } result.info.mipmaps = i; } return result; }
void* initializeNotifier(void (*process)(uint64_t, void*), void *param, int32_t *status) { if (!process) { *status = NULL_PARAMETER; return nullptr; } if (!notifierAtexitRegistered.test_and_set()) std::atexit(cleanupNotifierAtExit); if (notifierRefCount.fetch_add(1) == 0) { std::lock_guard<priority_mutex> sync(notifierInterruptMutex); // create manager and alarm if not already created if (!notifierManager) { notifierManager = new tInterruptManager(1 << kTimerInterruptNumber, false, status); notifierManager->registerHandler(alarmCallback, NULL, status); notifierManager->enable(status); } if (!notifierAlarm) notifierAlarm = tAlarm::create(status); } std::lock_guard<priority_recursive_mutex> sync(notifierMutex); // create notifier structure and add to list Notifier* notifier = new Notifier(); notifier->prev = nullptr; notifier->next = notifiers; if (notifier->next) notifier->next->prev = notifier; notifier->param = param; notifier->process = process; notifiers = notifier; return notifier; }
void cleanNotifier(void* notifier_pointer, int32_t *status) { { std::lock_guard<priority_recursive_mutex> sync(notifierMutex); Notifier* notifier = (Notifier*)notifier_pointer; // remove from list and delete if (notifier->prev) notifier->prev->next = notifier->next; if (notifier->next) notifier->next->prev = notifier->prev; if (notifiers == notifier) notifiers = notifier->next; delete notifier; } if (notifierRefCount.fetch_sub(1) == 1) { std::lock_guard<priority_mutex> sync(notifierInterruptMutex); // if this was the last notifier, clean up alarm and manager if (notifierAlarm) { notifierAlarm->writeEnable(false, status); delete notifierAlarm; notifierAlarm = nullptr; } if (notifierManager) { notifierManager->disable(status); delete notifierManager; notifierManager = nullptr; } closestTrigger = UINT64_MAX; } }
void print(){ if(size==0) printf("<empty>\n"); for(int i = 0; i < size;i++) printf("%d ", arr[(head.load() + i)%capacity]); printf("\n"); }
void worker_thread(int i, class Barrier& barrier1, class Barrier& barrier2) { { // std::lock_guard<std::mutex> lk(m); std::lock_guard<std::mutex> lk_guard(m); std::cout << "Worker thread " << i << " has arrived." << std::endl; } barrier1.wait(); { std::lock_guard<std::mutex> lk_guard(m); std::cout << "counts changing2, processed_all: " << processed_all << ", count > max:" << (arrived_count < allowed_max) << std::endl; arrived_count++; processed_count--; std::cout << "counts changing3, processed: " << processed_count << ", arrived:" << arrived_count<< std::endl; } { std::lock_guard<std::mutex> lk_guard(m); if (arrived_count.load() >= allowed_max) { std::cout << "Enough arrived, about to open floodgate #1" << std::endl; arrived_all = true; processed_all = false; // for (int i = 0; i < allowed_max; i++) { // cv1.notify_one(); // } } std::cout << "about to reach 2nd barrier:" << arrived_count<< std::endl; } // std::unique_lock<std::mutex> lk1(barrier1); barrier2.wait(); // cv1.wait(lk1, []{return (processed_count < allowed_max) && arrived_all;}); { std::lock_guard<std::mutex> lk_guard(m); processed_count++; arrived_count--; } // critical section would go here... then increment processed_count // report after critical section { std::lock_guard<std::mutex> lk(m); std::cout << "Worker thread " << i << " data processing completed" << std::endl; if (processed_count == allowed_max) { std::cout << "Group finished, about to open floodgate #2" << std::endl; processed_all = true; arrived_all = false; // for (int i = 0; i < allowed_max; i++) { // cv2.notify_one(); // } } } }
void testit(std::atomic_int& count) { std::default_random_engine generator; std::uniform_int_distribution<int> distribution(1, 10); auto sleep_time = std::bind(distribution, generator); std::this_thread::sleep_for(std::chrono::microseconds(sleep_time())); ++count; if(count.load() == 5) { g_condition.notify_one(); } }
Order::Order(int clientAssignedId, const std::string& account, const std::string& security, double price, int amount, Operation operation, OrderType type) : m_id(gs_id.fetch_add(1)), m_clientAssignedId(clientAssignedId), m_account(account), m_security(security), m_price(price), m_amount(amount), m_operation(operation), m_type(type), m_state(State::Unsubmitted) { }
bool add(int val){ enqLock.lock(); if((size+1) > capacity){ if(addremdbg) printf("af %d\n", val); enqLock.unlock(); return false; } if(addremdbg) printf("ap %d\n", val); arr[tail] = val; tail = (tail.load()+1)%capacity; size++; enqLock.unlock(); return true; }
inline void thread_pool::execute(delegate_type e) { if (fc_.fetch_sub(1, ::std::memory_order_relaxed) <= 0) { spawn_thread(); } // else do nothing { ::std::lock_guard<decltype(cm_)> l(cm_); delegates_.emplace_back(::std::move(e)); } cv_.notify_one(); }
int main () { using namespace shmdata; { // direct access writer with one reader Writer w("/tmp/check-stress", sizeof(Frame), "application/x-check-shmdata", &logger); assert(w); // init { Frame frame; assert(w.copy_to_shm(&frame, sizeof(Frame))); } Reader r("/tmp/check-stress", [](void *data, size_t size){ // auto frame = static_cast<Frame *>(data); // std::cout << "(0) new data for client " // << frame->count // << " (size " << size << ")" // << std::endl; }, nullptr, nullptr, &logger); std::cout << "one reader" << std::endl; assert(r); auto reader_handle = std::async(std::launch::async, reader); while (1 != done.load()) { // the following is locking the shared memory for writing auto access = w.get_one_write_access(); assert(access); access->notify_clients(sizeof(Frame)); auto frame = static_cast<Frame *>(access->get_mem()); frame->count++; } assert(reader_handle.get()); } std::this_thread::sleep_for (std::chrono::milliseconds(1000)); std::cout << "fin" << std::endl; return 0; }
int main(int argc, char** argv) { if (argc != 8) { printf("%s sAddr1 sAddr2 sAddr3 iChannelNum iWorkerNumPerChannel iCountPerWorker iEntityNum\n", argv[0]); exit(-1); } std::vector<std::string> vecIPList; for (int i = 1; i <= 3; ++i) vecIPList.push_back(argv[i]); int iChannelNum = atoi(argv[4]); int iWorkerNumPerChannel = atoi(argv[5]); int iCountPerWorker = atoi(argv[6]); uint64_t iEntityNum = atoi(argv[7]); clsUUIDGenerator::GetInstance()->Init(); for (int i = 0; i < iChannelNum; ++i) { std::shared_ptr<clsClient> poClient(new clsClient(&vecIPList)); for (int j = 0; j < iWorkerNumPerChannel; ++j) { clsRWStressTester* poTester = new clsRWStressTester(poClient, iCountPerWorker, iEntityNum); poTester->Start(); } } while (s_iStopCnt.load() == 0) { sleep(1); s_oStat.Print(); } printf("Fail %lu\n", s_iFailCnt.load()); return 0; }
void handle_subscribe_multiple (int argc, const char *argv[]) { uint32_t count = atoi(argv[1]); pthread_t *tid; CommandContext context(argc, argv, NULL); // Create N threads tid = new pthread_t[count]; for (int i = 0; i < count; i++) { pthread_create(&tid[i], NULL, proc, (void *) &context); } // Give few mins to subscribe all sleep(5); // Reset id some_id.store(0); // Wait for them to finish for (int i = 0; i < count; i++) { pthread_join(tid[i], NULL); } }
HAL_NotifierHandle HAL_InitializeNotifier(HAL_NotifierProcessFunction process, void* param, int32_t* status) { if (!process) { *status = NULL_PARAMETER; return 0; } if (!notifierAtexitRegistered.test_and_set()) std::atexit(cleanupNotifierAtExit); if (notifierRefCount.fetch_add(1) == 0) { std::lock_guard<priority_mutex> sync(notifierInterruptMutex); // create manager and alarm if not already created if (!notifierManager) { notifierManager = std::make_unique<tInterruptManager>( 1 << kTimerInterruptNumber, false, status); notifierManager->registerHandler(alarmCallback, nullptr, status); notifierManager->enable(status); } if (!notifierAlarm) notifierAlarm.reset(tAlarm::create(status)); } std::lock_guard<priority_recursive_mutex> sync(notifierMutex); std::shared_ptr<Notifier> notifier = std::make_shared<Notifier>(); HAL_NotifierHandle handle = notifierHandles.Allocate(notifier); if (handle == HAL_kInvalidHandle) { *status = HAL_HANDLE_ERROR; return HAL_kInvalidHandle; } // create notifier structure and add to list notifier->next = notifiers; if (notifier->next) notifier->next->prev = notifier; notifier->param = param; notifier->process = process; notifier->handle = handle; notifier->threaded = false; notifiers = notifier; return handle; }
bool reader(){ { // creating one reader std::this_thread::sleep_for (std::chrono::milliseconds(10)); Reader r("/tmp/check-stress", [](void *data, size_t size){ // auto frame = static_cast<Frame *>(data); // std::cout << "(one reader) new data for client " // << frame->count // << " (size " << size << ")" // << std::endl; }, nullptr, nullptr, &logger); assert(r); std::cout << "one more reader" << std::endl; std::this_thread::sleep_for (std::chrono::milliseconds(1000)); } std::cout << "one less reader" << std::endl; { // creating five readers std::this_thread::sleep_for (std::chrono::milliseconds(10)); Reader r1("/tmp/check-stress", [](void *data, size_t size){ // auto frame = static_cast<Frame *>(data); // std::cout << "(1) new data for client " // << frame->count // << " (size " << size << ")" // << std::endl; }, nullptr, nullptr, &logger); assert(r1); Reader r2("/tmp/check-stress", [](void *data, size_t size){ // auto frame = static_cast<Frame *>(data); // std::cout << "(2) new data for client " // << frame->count // << " (size " << size << ")" // << std::endl; }, nullptr, nullptr, &logger); assert(r2); Reader r3("/tmp/check-stress", [](void *data, size_t size){ // auto frame = static_cast<Frame *>(data); // std::cout << "(3) new data for client " // << frame->count // << " (size " << size << ")" // << std::endl; }, nullptr, nullptr, &logger); assert(r3); Reader r4("/tmp/check-stress", [](void *data, size_t size){ // auto frame = static_cast<Frame *>(data); // std::cout << "(4) new data for client " // << frame->count // << " (size " << size << ")" // << std::endl; }, nullptr, nullptr, &logger); assert(r4); Reader r5("/tmp/check-stress", [](void *data, size_t size){ // auto frame = static_cast<Frame *>(data); // std::cout << "(5) new data for client " // << frame->count // << " (size " << size << ")" // << std::endl; }, nullptr, nullptr, &logger); assert(r5); std::cout << "five more reader" << std::endl; std::this_thread::sleep_for (std::chrono::milliseconds(1000)); } std::this_thread::sleep_for (std::chrono::milliseconds(100)); done.store(1); std::cout << "done set to 1" << std::endl; return true; }
// ------------------------------------------------------------------------ void increaseGLCommandFunctionCount(int count) { m_gl_cmd_function_count.fetch_add(count); }
static void *doit(int id, Config &conf) { FCGX_Request request; if(FCGX_InitRequest(&request, socketId.load(), 0) != 0) { //ошибка при инициализации структуры запроса printf("Can not init request\n"); return NULL; } Router router(&request, &conf); router.addHandler("OPTIONS", "/users/login", &OptUsersLogin); router.addHandler("GET", "/users/login", &UsersInfo); router.addHandler("POST", "/users/login", &PostUsersLogin); router.addHandler("OPTIONS", "/users/add", &OptUsersAdd); router.addHandler("POST", "/users/add", &PostUsersAdd); router.addHandler("OPTIONS", ".*", &OptDirs); router.addHandler("OPTIONS", "/dirs/(?<id>\\d+)", &OptDirs); router.addHandler("POST", "/dirs", &PostCreateDir); router.addHandler("GET", "/dirs/(\\d+)", &GetDir); router.addHandler("DELETE", "/dirs/(\\d+)", &DelDir); router.addHandler("POST", "/files/(\\d+)/(.+)", &PutFile); router.addHandler("GET", "/files/(\\d+)", &GetFile); router.addHandler("DELETE", "/files/(\\d+)", &DelFile); for(;;) { static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&accept_mutex); int rc = FCGX_Accept_r(&request); pthread_mutex_unlock(&accept_mutex); if(rc < 0) { //ошибка при получении запроса printf("Can not accept new request\n"); break; } std::streambuf * cin_streambuf = std::cin.rdbuf(); std::streambuf * cout_streambuf = std::cout.rdbuf(); std::streambuf * cerr_streambuf = std::cerr.rdbuf(); fcgi_streambuf cin_fcgi_streambuf(request.in); fcgi_streambuf cout_fcgi_streambuf(request.out); fcgi_streambuf cerr_fcgi_streambuf(request.err); std::cin.rdbuf(&cin_fcgi_streambuf); std::cout.rdbuf(&cout_fcgi_streambuf); std::cerr.rdbuf(&cerr_fcgi_streambuf); try { router.Run(); } catch (Error &e) { router.SetStatus(e.http_code()); router.AddHeader("Content-Type", "application/json; charset=utf-8"); router.AddContent(e.what()); router.AcceptContent(); } catch (std::exception &e) { std::cerr << e.what(); router.SetStatus(Httpstatus::InternalServerError); router.AddHeader("Content-Type", "text/plain; charset=utf-8"); router.AddContent(e.what()); router.AcceptContent(); } FCGX_Finish_r(&request); //завершающие действия - запись статистики, логгирование ошибок и т.п. router.Cleanup(); std::cin.rdbuf(cin_streambuf); std::cout.rdbuf(cout_streambuf); std::cerr.rdbuf(cerr_streambuf); } return NULL; }
namespace glws { static char TAG[]="apitrace"; static JavaVM *s_javaVM = nullptr; static jobject s_activityObject = nullptr; static std::mutex s_activityObjectMutex; static jmethodID s_setSurfaceSizeMethodID = nullptr; static jfieldID s_descriptor = nullptr; typedef std::shared_ptr<ANativeWindow> AndroidWindow; static AndroidWindow s_currentNativeWindow; static std::atomic_int s_currentNativeWindowId(0); static std::mutex s_currentNativeWindowMutex; static int s_stdout_fd = -1; static int s_stderr_fd = -1; static std::mutex s_stateMutex; static std::condition_variable s_stateWait; static EGLDisplay eglDisplay = EGL_NO_DISPLAY; static char const *eglExtensions = NULL; static bool has_EGL_KHR_create_context = false; struct ResourceTracker; static std::mutex s_resourcesMutex; static std::vector<ResourceTracker*> s_resources; class FdWriter : public std::streambuf { public: FdWriter(int fd) { m_fd = fd; int opts = fcntl(m_fd, F_GETFL); opts = opts & (~O_NONBLOCK); fcntl(m_fd, F_SETFL, opts); } // basic_streambuf interface protected: std::streamsize xsputn(const char_type *__s, std::streamsize __n) { std::streamsize ret = 0; while( __n ) { ssize_t written = write(m_fd, __s, __n); if (written > 0) { __n -= written; __s += written; ret += written; } else { switch (errno) { case EBADF: case EINVAL: case EPIPE: std::exit(1); break; } } } return ret; } int_type overflow(int_type __c) { return xsputn(reinterpret_cast<const char_type *>(&__c), 1) == 1 ? __c : traits_type::eof(); } private: int m_fd = -1; }; static EGLenum translateAPI(glprofile::Profile profile) { switch (profile.api) { case glprofile::API_GL: return EGL_OPENGL_API; case glprofile::API_GLES: return EGL_OPENGL_ES_API; default: assert(0); return EGL_NONE; } } /* Must be called before * * - eglCreateContext * - eglGetCurrentContext * - eglGetCurrentDisplay * - eglGetCurrentSurface * - eglMakeCurrent (when its ctx parameter is EGL_NO_CONTEXT ), * - eglWaitClient * - eglWaitNative */ static void bindAPI(EGLenum api) { if (eglBindAPI(api) != EGL_TRUE) { std::cerr << "error: eglBindAPI failed\n"; exit(1); } } struct EglVisual : public Visual { EglVisual(Profile prof) : Visual(prof) {} EGLConfig config = 0; EGLint format = -1; }; struct ResourceTracker { ResourceTracker() { s_resourcesMutex.lock(); s_resources.push_back(this); s_resourcesMutex.unlock(); } virtual ~ResourceTracker() { s_resourcesMutex.lock(); s_resources.erase(std::find(s_resources.begin(), s_resources.end(), this)); s_resourcesMutex.unlock(); } }; class EglDrawable : public Drawable, private ResourceTracker { public: EglDrawable(const Visual *vis, int w, int h, bool pbuffer) : Drawable(vis, w, h, pbuffer), api(EGL_OPENGL_ES_API), windowId(0) { eglWaitNative(EGL_CORE_NATIVE_ENGINE); const EglVisual * eglVisual = static_cast<const EglVisual *>(visual); update(); ANativeWindow_setBuffersGeometry(window.get(), 0, 0, eglVisual->format); surface = eglCreateWindowSurface(eglDisplay, eglVisual->config, window.get(), NULL); } ~EglDrawable() { eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(eglDisplay, surface); eglWaitClient(); eglWaitNative(EGL_CORE_NATIVE_ENGINE); } void recreate(void) { EGLContext currentContext = eglGetCurrentContext(); EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW); EGLSurface currentReadSurface = eglGetCurrentSurface(EGL_READ); bool rebindDrawSurface = currentDrawSurface == surface; bool rebindReadSurface = currentReadSurface == surface; if (rebindDrawSurface || rebindReadSurface) { eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(eglDisplay, surface); } const EglVisual * eglVisual = static_cast<const EglVisual *>(visual); ANativeWindow_setBuffersGeometry(window.get(), 0, 0, eglVisual->format); surface = eglCreateWindowSurface(eglDisplay, eglVisual->config, (EGLNativeWindowType)window.get(), NULL); if (rebindDrawSurface || rebindReadSurface) eglMakeCurrent(eglDisplay, surface, surface, currentContext); } void resize(int w, int h) { if (w == width && h == height) { return; } eglWaitClient(); Drawable::resize(w, h); resizeSurface(w, h); } void show(void) { if (visible) { return; } eglWaitClient(); eglWaitNative(EGL_CORE_NATIVE_ENGINE); Drawable::show(); } void swapBuffers(void) { if (update()) recreate(); bindAPI(api); eglSwapBuffers(eglDisplay, surface); } private: inline bool update() { if (windowId.load() == s_currentNativeWindowId.load()) return false; s_currentNativeWindowMutex.lock(); window = s_currentNativeWindow; windowId.store(s_currentNativeWindowId.load()); s_currentNativeWindowMutex.unlock(); return true; } void resizeSurface(int w, int h) { JNIEnv *env = nullptr; if (JNI_OK != s_javaVM->AttachCurrentThread(&env, nullptr)) { __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed"); std::exit(1); } s_activityObjectMutex.lock(); env->CallVoidMethod(s_activityObject, s_setSurfaceSizeMethodID, w, h); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); } s_activityObjectMutex.unlock(); s_javaVM->DetachCurrentThread(); } public: EGLSurface surface; EGLenum api; private: AndroidWindow window; std::atomic_int windowId; }; class EglContext : public Context, private ResourceTracker { public: EGLContext context; EglContext(const Visual *vis, EGLContext ctx) : Context(vis), context(ctx) {} ~EglContext() { eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(eglDisplay, context); } }; void init(void) { eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (eglDisplay == EGL_NO_DISPLAY) { std::cerr << "error: unable to get EGL display\n"; exit(1); } EGLint major, minor; if (!eglInitialize(eglDisplay, &major, &minor)) { std::cerr << "error: unable to initialize EGL display\n"; exit(1); } eglExtensions = eglQueryString(eglDisplay, EGL_EXTENSIONS); has_EGL_KHR_create_context = checkExtension("EGL_KHR_create_context", eglExtensions); } void cleanup(void) { while (!s_resources.empty()) { delete *s_resources.rbegin(); } if (eglDisplay != EGL_NO_DISPLAY) { eglTerminate(eglDisplay); } eglDisplay = EGL_NO_DISPLAY; eglExtensions = nullptr; has_EGL_KHR_create_context = false; s_stateMutex.lock(); close(s_stdout_fd); close(s_stderr_fd); s_stdout_fd = -1; s_stderr_fd = -1; s_stateMutex.unlock(); } Visual * createVisual(bool doubleBuffer, unsigned samples, Profile profile) { EGLint api_bits; if (profile.api == glprofile::API_GL) { api_bits = EGL_OPENGL_BIT; if (profile.core && !has_EGL_KHR_create_context) { return NULL; } } else if (profile.api == glprofile::API_GLES) { switch (profile.major) { case 1: api_bits = EGL_OPENGL_ES_BIT; break; case 3: if (has_EGL_KHR_create_context) { api_bits = EGL_OPENGL_ES3_BIT; break; } /* fall-through */ case 2: api_bits = EGL_OPENGL_ES2_BIT; break; default: return NULL; } } else { assert(0); return NULL; } Attributes<EGLint> attribs; attribs.add(EGL_SURFACE_TYPE, EGL_WINDOW_BIT); attribs.add(EGL_RED_SIZE, 1); attribs.add(EGL_GREEN_SIZE, 1); attribs.add(EGL_BLUE_SIZE, 1); attribs.add(EGL_ALPHA_SIZE, 1); attribs.add(EGL_DEPTH_SIZE, 1); attribs.add(EGL_STENCIL_SIZE, 1); attribs.add(EGL_RENDERABLE_TYPE, api_bits); attribs.end(EGL_NONE); EGLint num_configs = 0; if (!eglGetConfigs(eglDisplay, NULL, 0, &num_configs) || num_configs <= 0) { return NULL; } std::vector<EGLConfig> configs(num_configs); if (!eglChooseConfig(eglDisplay, attribs, &configs[0], num_configs, &num_configs) || num_configs <= 0) { return NULL; } // We can't tell what other APIs the trace will use afterwards, therefore // try to pick a config which supports the widest set of APIs. int bestScore = -1; EGLConfig config = configs[0]; for (EGLint i = 0; i < num_configs; ++i) { EGLint renderable_type = EGL_NONE; eglGetConfigAttrib(eglDisplay, configs[i], EGL_RENDERABLE_TYPE, &renderable_type); int score = 0; assert(renderable_type & api_bits); renderable_type &= ~api_bits; if (renderable_type & EGL_OPENGL_ES2_BIT) { score += 1 << 4; } if (renderable_type & EGL_OPENGL_ES3_BIT) { score += 1 << 3; } if (renderable_type & EGL_OPENGL_ES_BIT) { score += 1 << 2; } if (renderable_type & EGL_OPENGL_BIT) { score += 1 << 1; } if (score > bestScore) { config = configs[i]; bestScore = score; } } assert(bestScore >= 0); EGLint visual_id = -1; if (!eglGetConfigAttrib(eglDisplay, config, EGL_NATIVE_VISUAL_ID, &visual_id)) { assert(0); return NULL; } assert(visual_id != -1); EglVisual *visual = new EglVisual(profile); visual->config = config; visual->format = visual_id; return visual; } Drawable * createDrawable(const Visual *visual, int width, int height, bool pbuffer) { return new EglDrawable(visual, width, height, pbuffer); } Context * createContext(const Visual *_visual, Context *shareContext, bool debug) { Profile profile = _visual->profile; const EglVisual *visual = static_cast<const EglVisual *>(_visual); EGLContext share_context = EGL_NO_CONTEXT; EGLContext context; Attributes<EGLint> attribs; if (shareContext) { share_context = static_cast<EglContext*>(shareContext)->context; } int contextFlags = 0; if (profile.api == glprofile::API_GL) { if (has_EGL_KHR_create_context) { attribs.add(EGL_CONTEXT_MAJOR_VERSION_KHR, profile.major); attribs.add(EGL_CONTEXT_MINOR_VERSION_KHR, profile.minor); int profileMask = profile.core ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; attribs.add(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, profileMask); if (profile.forwardCompatible) { contextFlags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; } } else if (profile.versionGreaterOrEqual(3, 2)) { std::cerr << "error: EGL_KHR_create_context not supported\n"; return NULL; } } else if (profile.api == glprofile::API_GLES) { if (has_EGL_KHR_create_context) { attribs.add(EGL_CONTEXT_MAJOR_VERSION_KHR, profile.major); attribs.add(EGL_CONTEXT_MINOR_VERSION_KHR, profile.minor); } else { attribs.add(EGL_CONTEXT_CLIENT_VERSION, profile.major); } } else { assert(0); return NULL; } if (debug) { contextFlags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; } if (contextFlags && has_EGL_KHR_create_context) { attribs.add(EGL_CONTEXT_FLAGS_KHR, contextFlags); } attribs.end(EGL_NONE); EGLenum api = translateAPI(profile); bindAPI(api); context = eglCreateContext(eglDisplay, visual->config, share_context, attribs); if (!context) { if (debug) { // XXX: Mesa has problems with EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR // with OpenGL ES contexts, so retry without it return createContext(_visual, shareContext, false); } return NULL; } return new EglContext(visual, context); } bool makeCurrentInternal(Drawable *drawable, Context *context) { if (!drawable || !context) { return eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } else { EglDrawable *eglDrawable = static_cast<EglDrawable *>(drawable); EglContext *eglContext = static_cast<EglContext *>(context); EGLBoolean ok; EGLenum api = translateAPI(eglContext->profile); bindAPI(api); ok = eglMakeCurrent(eglDisplay, eglDrawable->surface, eglDrawable->surface, eglContext->context); if (ok) { eglDrawable->api = api; } return ok; } } bool processEvents(void) { return false; } static void readParamsAndStartTrace() { std::string paramsLine; char buff[4096]; while (true) { ssize_t sz = read(s_stdout_fd, buff, 4095); if (sz < 0) { cleanup(); return ; } buff[sz] = '\0'; paramsLine += buff; if (paramsLine.find('\n') > 0) break; } std::regex word_regex("(\"[^\"]*\")|([^\\s]+)"); auto words_begin = std::sregex_iterator(paramsLine.begin(), paramsLine.end(), word_regex); auto words_end = std::sregex_iterator(); std::vector<std::string> paramsVector; std::vector<char *> params; params.push_back(TAG); for (std::sregex_iterator i = words_begin; i != words_end; ++i) { paramsVector.push_back(i->str()); params.push_back(const_cast<char*>(paramsVector.back().c_str())); } { std::unique_lock<std::mutex> lock(s_stateMutex); __android_log_print(ANDROID_LOG_DEBUG, TAG, "Wait for stderr socket"); s_stateWait.wait(lock, []{return s_stderr_fd != -1; }); } __android_log_print(ANDROID_LOG_DEBUG, TAG, "Start retrace"); optind = 1; optreset = 1; main(params.size(), ¶ms[0]); cleanup(); // Remove "std::exit" after apitrace will cleanup its static variables. std::exit(0); // goodbye cruel world ! } static inline int getFd(JNIEnv* env, jobject obj) { return env->GetIntField(obj, s_descriptor); } static bool setFd(std::ostream &stream, int *state_fd, int fd) { std::lock_guard<std::mutex> lock(s_stateMutex); if (*state_fd != -1) return false; *state_fd = fd; delete dynamic_cast<FdWriter*>(stream.rdbuf(new FdWriter(fd))); return true; } static jboolean setStdoutFileDescriptor(JNIEnv *env, jobject /*object*/, jobject fd) { bool res = setFd(std::cout, &s_stdout_fd, getFd(env, fd)); if (res) std::async(std::launch::async, glws::readParamsAndStartTrace); return res; } static jboolean setStderrFileDescriptor(JNIEnv *env, jobject /*object*/, jobject fd) { bool res = setFd(std::cerr, &s_stderr_fd, getFd(env, fd)); if (res) s_stateWait.notify_one(); return res; } static void onActivityCreated(JNIEnv *env, jobject /*object*/, jobject activity) { s_activityObjectMutex.lock(); s_activityObject = env->NewGlobalRef(activity); s_activityObjectMutex.unlock(); } static void onSurfaceCreated(JNIEnv *env, jobject /*object*/, jobject surface) { s_currentNativeWindowMutex.lock(); s_currentNativeWindow = AndroidWindow(ANativeWindow_fromSurface(env, surface), [](ANativeWindow *w) { ANativeWindow_release(w); }); ++s_currentNativeWindowId; s_currentNativeWindowMutex.unlock(); } static void onSurfaceChanged(JNIEnv *env, jobject /*object*/, jobject surface, int /*format*/, int /*width*/, int /*height*/) { s_currentNativeWindowMutex.lock(); s_currentNativeWindow = AndroidWindow(ANativeWindow_fromSurface(env, surface), [](ANativeWindow *w) { ANativeWindow_release(w); }); ++s_currentNativeWindowId; s_currentNativeWindowMutex.unlock(); } static void onSurfaceRedrawNeeded(JNIEnv */*env*/, jobject /*object*/, jobject /*surface*/) { } static void onSurfaceDestroyed(JNIEnv */*env*/, jobject /*object*/) { s_currentNativeWindowMutex.lock(); s_currentNativeWindow.reset(); s_currentNativeWindowId.store(0); s_currentNativeWindowMutex.unlock(); } static void onActivityDestroyed(JNIEnv *env, jobject /*object*/) { s_activityObjectMutex.lock(); env->DeleteGlobalRef(s_activityObject); s_activityObject = nullptr; s_activityObjectMutex.unlock(); } static JNINativeMethod methods[] = { {"setStdoutFileDescriptor", "(Ljava/io/FileDescriptor;)Z", (void *)setStdoutFileDescriptor}, {"setStderrFileDescriptor", "(Ljava/io/FileDescriptor;)Z", (void *)setStderrFileDescriptor}, {"onActivityCreatedNative", "(Lapitrace/github/io/eglretrace/RetraceActivity;)V", (void *)onActivityCreated}, {"onSurfaceCreatedNative", "(Landroid/view/Surface;)V", (void *)onSurfaceCreated}, {"onSurfaceChangedNative", "(Landroid/view/Surface;III)V", (void *)onSurfaceChanged}, {"onSurfaceRedrawNeededNative", "(Landroid/view/Surface;)V", (void *)onSurfaceRedrawNeeded}, {"onSurfaceDestroyedNative", "()V", (void *)onSurfaceDestroyed}, {"onActivityDestroyedNative", "()V", (void *)onActivityDestroyed} }; } /* namespace glws */
int main(int argc, char **argv) { int i; std::ostringstream conffile; conffile << SYSCONFDIR << "/restfsd.ini"; Config conf(conffile.str()); const int THREAD_COUNT = conf.GetInteger("main","threads",2); std::thread *id = new std::thread[THREAD_COUNT]; FCGX_Init(); socketId.store( FCGX_OpenSocket(conf.get("main","listen").c_str(), 20) ); if(socketId < 0) { printf("Socket isn't opened\n"); return 1; } //~ int pid; //~ pid = fork(); //~ if (pid == -1) //~ { //~ printf("Error: Start Daemon failed (%s)\n", strerror(errno)); //~ return -1; //~ } //~ else if (!pid) //~ { //~ umask(0); //~ setsid(); //~ //chdir("/home/sokol"); for(i = 0; i < THREAD_COUNT; i++) { id[i] = std::thread( doit, i, std::ref(conf) ); } //~ sleep(1); //~ std::cout << "main1 " << conf.get("test","test") << std::endl; //~ for(i = 0; i < THREAD_COUNT; i++) //~ { //~ id[i].join(); //~ id[i].detach(); //~ } //~ while(true) { //~ //std::cout << "while" << std::endl; //~ for(i = 0; i < THREAD_COUNT; i++) //~ { //~ id[i].join(); //~ std::cout << "thread[" << i << "].get_id: " << id[i].get_id() << std::endl; //~ if (id[i].joinable()) //~ { //~ id[i].join(); //~ } else //~ { //~ std::cout << "thread[" << i << "]: starting" << std::endl; //~ id[i] = std::thread( doit, i, std::ref(conf) ); //~ } //~ } //~ //sleep(1); //~ } //~ close(STDIN_FILENO); //~ close(STDOUT_FILENO); //~ close(STDERR_FILENO); for(i = 0; i < THREAD_COUNT; i++) { id[i].join(); } //~ std::cout << "main2" << conf.get("test","test") << std::endl; return 0; //~ } else //~ { //~ printf("Start Daemon pid=(%d)\n", pid); //~ return 0; //~ } }