int attribute_hidden __pthread_enable_asynccancel (void) { struct pthread *self = THREAD_SELF; int oldval; if (is_recording()) { pthread_log_record (0, PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling, 1); oldval = THREAD_GETMEM (self, cancelhandling); pthread_log_record (oldval, PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling, 0); } else if (is_replaying()) { pthread_log_replay (PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling); oldval = pthread_log_replay (PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling); } else { oldval = THREAD_GETMEM (self, cancelhandling); } while (1) { int newval = oldval | CANCELTYPE_BITMASK; if (newval == oldval) break; int curval; if (is_recording()) { pthread_log_record (0, PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling, 1); curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, oldval); pthread_log_record (curval, PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling, 0); } else if (is_replaying()) { pthread_log_replay (PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling); curval = pthread_log_replay (PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling); } else { curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, oldval); } if (__builtin_expect (curval == oldval, 1)) { if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) { THREAD_SETMEM (self, result, PTHREAD_CANCELED); __do_cancel (); } break; } /* Prepare the next round. */ oldval = curval; } return oldval; }
void __cleanup_fct_attribute __pthread_register_cancel_defer (__pthread_unwind_buf_t *buf) { struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; struct pthread *self = THREAD_SELF; /* Store old info. */ ibuf->priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); ibuf->priv.data.cleanup = THREAD_GETMEM (self, cleanup); int cancelhandling; if (is_recording()) { pthread_log_record (0, PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling, 1); cancelhandling = THREAD_GETMEM (self, cancelhandling); pthread_log_record (cancelhandling, PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling, 0); } else if (is_replaying()) { pthread_log_replay (PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling); cancelhandling = pthread_log_replay (PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling); } else { cancelhandling = THREAD_GETMEM (self, cancelhandling); } /* Disable asynchronous cancellation for now. */ if (__builtin_expect (cancelhandling & CANCELTYPE_BITMASK, 0)) while (1) { int curval; if (is_recording()) { pthread_log_record (0, PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling, 1); curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, cancelhandling & ~CANCELTYPE_BITMASK, cancelhandling); pthread_log_record (curval, PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling, 0); } else if (is_replaying()) { pthread_log_replay (PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling); curval = pthread_log_replay (PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling); } else { curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, cancelhandling & ~CANCELTYPE_BITMASK, cancelhandling); } if (__builtin_expect (curval == cancelhandling, 1)) /* Successfully replaced the value. */ break; /* Prepare for the next round. */ cancelhandling = curval; } ibuf->priv.data.canceltype = (cancelhandling & CANCELTYPE_BITMASK ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED); /* Store the new cleanup handler info. */ THREAD_SETMEM (self, cleanup_jmp_buf, (struct pthread_unwind_buf *) buf); }
void __cleanup_fct_attribute __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *buf) { struct pthread *self = THREAD_SELF; struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; THREAD_SETMEM (self, cleanup_jmp_buf, ibuf->priv.data.prev); int cancelhandling; if (is_recording()) { pthread_log_record (0, PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling, 1); cancelhandling = THREAD_GETMEM (self, cancelhandling); pthread_log_record (cancelhandling, PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling, 0); } else if (is_replaying()) { pthread_log_replay (PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling); cancelhandling = pthread_log_replay (PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling); } else { cancelhandling = THREAD_GETMEM (self, cancelhandling); } if (ibuf->priv.data.canceltype != PTHREAD_CANCEL_DEFERRED && (cancelhandling & CANCELTYPE_BITMASK) == 0) { while (1) { int curval; if (is_recording()) { pthread_log_record (0, PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling, 1); curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, cancelhandling | CANCELTYPE_BITMASK, cancelhandling); pthread_log_record (curval, PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling, 0); } else if (is_replaying()) { pthread_log_replay (PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling); curval = pthread_log_replay (PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling); } else { curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, cancelhandling | CANCELTYPE_BITMASK, cancelhandling); } if (__builtin_expect (curval == cancelhandling, 1)) /* Successfully replaced the value. */ break; /* Prepare for the next round. */ cancelhandling = curval; } CANCELLATION_P (self); } }
void video_manager::toggle_record_movie() { if (!is_recording()) { begin_recording(nullptr, MF_MNG); machine().popmessage("REC START"); } else { end_recording(MF_MNG); machine().popmessage("REC STOP"); } }
void video_manager::toggle_record_movie(movie_format format) { if (!is_recording()) { begin_recording(nullptr, format); machine().popmessage("REC START (%s)", format == MF_MNG ? "MNG" : "AVI"); } else { end_recording(format); machine().popmessage("REC STOP (%s)", format == MF_MNG ? "MNG" : "AVI"); } }
// REPLAY: The above function only modifies cancelhandling void internal_function attribute_hidden __pthread_disable_asynccancel (int oldtype) { if (is_recording()) { struct pthread *self = THREAD_SELF; pthread_log_record (0, PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling, 1); __internal_pthread_disable_asynccancel(oldtype); pthread_log_record (0, PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling, 0); } else if (is_replaying()) { struct pthread *self = THREAD_SELF; pthread_log_replay (PTHREAD_CANCELHANDLING_ENTER, (u_long) &self->cancelhandling); pthread_log_replay (PTHREAD_CANCELHANDLING_EXIT, (u_long) &self->cancelhandling); } else { __internal_pthread_disable_asynccancel(oldtype); } }
static ssize_t scribe_do_read(struct file *file, char __user *buf, ssize_t len, loff_t *ppos) { struct scribe_ps *scribe = current->scribe; int force_block = 0; ssize_t ret; if (!is_scribed(scribe)) return do_read(file, buf, len, ppos, force_block); if (is_kernel_copy()) goto out; if (!should_scribe_data(scribe)) goto out; scribe_need_syscall_ret(scribe); if (is_replaying(scribe)) { len = scribe->orig_ret; if (len <= 0) return len; force_block = 1; } if (is_deterministic(file)) goto out; scribe_data_non_det(); if (is_recording(scribe)) goto out; return scribe_emul_copy_to_user(scribe, buf, len); out: scribe->in_read_write = true; ret = do_read(file, buf, len, ppos, force_block); scribe->in_read_write = false; return ret; }
static int get_data_event(struct scribe_ps *scribe, struct data_desc *desc) { union scribe_event_data_union event; if (is_recording(scribe)) { event = scribe->prepared_data_event; if (event.generic) { scribe->prepared_data_event.generic = NULL; if (desc->do_info) { /* we're good */ } else if (desc->do_extra) { BUG_ON(event.extra->h.size < desc->size); event.extra->h.size = desc->size; } else { BUG_ON(event.regular->h.size < desc->size); event.regular->h.size = desc->size; } goto out; } if (desc->do_info) event.info = scribe_alloc_event( SCRIBE_EVENT_DATA_INFO); else if (desc->do_extra) event.extra = scribe_alloc_event_sized( SCRIBE_EVENT_DATA_EXTRA, desc->size); else event.regular = scribe_alloc_event_sized( SCRIBE_EVENT_DATA, desc->size); if (!event.generic) { scribe_kill(scribe->ctx, -ENOMEM); return -ENOMEM; } goto out; } else /* replaying */ { event = scribe->prepared_data_event; if (event.generic) { scribe->prepared_data_event.generic = NULL; goto out; } /* * Not using scribe_dequeue_event_sized() because we don't * really know the size (maybe we are in * scribe_prepare_data_event() and @desc->size would only be the * maximum size). */ /* * XXX XXX We cannot dequeue in the middle of the stream * because our data event may act as a fence. * So we'll peek, which means that we'll have to dequeue it * eventually. */ if (desc->do_info) event.generic = scribe_find_event_specific( scribe, SCRIBE_EVENT_DATA_INFO); else if (desc->do_extra) event.generic = scribe_find_event_specific( scribe, SCRIBE_EVENT_DATA_EXTRA); else event.generic = scribe_find_event_specific( scribe, SCRIBE_EVENT_DATA); if (IS_ERR(event.generic)) return PTR_ERR(event.generic); } out: desc->event = event; return 0; }
void video_manager::record_frame() { // ignore if nothing to do if (!is_recording()) return; // start the profiler and get the current time g_profiler.start(PROFILER_MOVIE_REC); attotime curtime = machine().time(); screen_device_iterator device_iterator = screen_device_iterator(machine().root_device()); screen_device_iterator::auto_iterator iter = device_iterator.begin(); for (uint32_t index = 0; index < (std::max)(m_mngs.size(), m_avis.size()); index++, iter++) { // create the bitmap create_snapshot_bitmap(iter.current()); // handle an AVI recording if ((index < m_avis.size()) && m_avis[index].m_avi_file) { avi_info_t &avi_info = m_avis[index]; // loop until we hit the right time while (avi_info.m_avi_next_frame_time <= curtime) { // write the next frame avi_file::error avierr = avi_info.m_avi_file->append_video_frame(m_snap_bitmap); if (avierr != avi_file::error::NONE) { g_profiler.stop(); // FIXME: double exit if this happens? end_recording_avi(index); break; } // advance time avi_info.m_avi_next_frame_time += avi_info.m_avi_frame_period; avi_info.m_avi_frame++; } } // handle a MNG recording if ((index < m_mngs.size()) && m_mngs[index].m_mng_file) { mng_info_t &mng_info = m_mngs[index]; // loop until we hit the right time while (mng_info.m_mng_next_frame_time <= curtime) { // set up the text fields in the movie info png_info pnginfo; if (mng_info.m_mng_frame == 0) { std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(emulator_info::get_build_version()); std::string text2 = std::string(machine().system().manufacturer).append(" ").append(machine().system().type.fullname()); pnginfo.add_text("Software", text1.c_str()); pnginfo.add_text("System", text2.c_str()); } // write the next frame screen_device *screen = iter.current(); const rgb_t *palette = (screen != nullptr && screen->has_palette()) ? screen->palette().palette()->entry_list_adjusted() : nullptr; int entries = (screen != nullptr && screen->has_palette()) ? screen->palette().entries() : 0; png_error error = mng_capture_frame(*mng_info.m_mng_file, pnginfo, m_snap_bitmap, entries, palette); if (error != PNGERR_NONE) { g_profiler.stop(); // FIXME: double exit if this happens? end_recording_mng(index); break; } // advance time mng_info.m_mng_next_frame_time += mng_info.m_mng_frame_period; mng_info.m_mng_frame++; } } if (!m_snap_native) { break; } } g_profiler.stop(); }
static ssize_t scribe_do_readv_writev(int type, struct file *file, const struct iovec __user * uvector, unsigned long nr_segs, loff_t *pos) { struct scribe_ps *scribe = current->scribe; struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov = iovstack; int force_block = 0; ssize_t ret, len = 0; if (!is_scribed(scribe)) return do_readv_writev(type, file, uvector, nr_segs, 0, pos, force_block); if (is_kernel_copy()) goto out; if (!should_scribe_data(scribe)) goto out; scribe_need_syscall_ret(scribe); if (is_replaying(scribe)) { len = scribe->orig_ret; if (len <= 0) { rw_copy_check_uvector(type, uvector, nr_segs, ARRAY_SIZE(iovstack), iovstack, &iov); ret = len; goto free; } force_block = 1; } if (type == READ) { if (is_deterministic(file)) goto out; scribe_data_non_det(); if (is_recording(scribe)) goto out; rw_copy_check_uvector(type, uvector, nr_segs, ARRAY_SIZE(iovstack), iovstack, &iov); ret = __do_loop_readv_writev(file, iov, nr_segs, len, pos, io_scribe_emul_copy_to_user); goto free; } out: scribe->in_read_write = true; ret = do_readv_writev(type, file, uvector, nr_segs, len, pos, force_block); scribe->in_read_write = false; free: if (iov != iovstack) kfree(iov); return ret; }