No locks, more lox #290 (#358)

* README/CMake: only require doctest 2.3.5

* man pages: remove talk of locking #290

* Remove locking from notcurses core #290

* Purge locking from notcurses core #290
This commit is contained in:
Nick Black 2020-02-18 20:03:20 -05:00 committed by GitHub
parent 887d4f1f79
commit e5d6685c92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 70 additions and 192 deletions

View File

@ -32,7 +32,7 @@ pkg_check_modules(AVUTIL REQUIRED libavutil>=56.0)
pkg_check_modules(SWSCALE REQUIRED libswscale>=5.0)
endif()
find_library(LIBRT rt)
find_package(doctest 2.3.6 REQUIRED)
find_package(doctest 2.3.5 REQUIRED)
# libnotcurses
file(GLOB NCSRCS CONFIGURE_DEPENDS src/lib/*.c)

View File

@ -113,7 +113,7 @@ that fine library.
* (build) CMake 3.14.0+
* (build+runtime) From NCURSES: terminfo 6.1+
* (OPTIONAL) (build+runtime) From FFMpeg: libswscale 5.0+, libavformat 57.0+, libavutil 56.0+
* (OPTIONAL) (testing) [Doctest](https://github.com/onqtam/doctest) 2.3.6+
* (OPTIONAL) (testing) [Doctest](https://github.com/onqtam/doctest) 2.3.5+
* (OPTIONAL) (documentation) [pandoc](https://pandoc.org/index.html) 1.19.2+
* (OPTIONAL) (python bindings): Python 3.7+, CFFI 1.13.2+
* (OPTIONAL) (rust bindings, colloquy): rust 1.40.0+, cargo 0.40.0+, cmake-rs 0.1.42+
@ -292,7 +292,8 @@ int notcurses_resize(struct notcurses* n, int* RESTRICT y, int* RESTRICT x);
// Return our current idea of the terminal dimensions in rows and cols.
static inline void
notcurses_term_dim_yx(struct notcurses* n, int* RESTRICT rows, int* RESTRICT cols){
notcurses_term_dim_yx(const struct notcurses* n, int* RESTRICT rows,
int* RESTRICT cols){
ncplane_dim_yx(notcurses_stdplane(n), rows, cols);
}
@ -396,7 +397,7 @@ typedef enum {
// according to 'align' within ncplane 'n'. Returns INT_MAX on invalid 'align'.
// Undefined behavior on negative 'c'.
static inline int
ncplane_align(struct ncplane* n, ncalign_e align, int c){
ncplane_align(const struct ncplane* n, ncalign_e align, int c){
if(align == NCALIGN_LEFT){
return 0;
}
@ -672,14 +673,14 @@ void ncplane_yx(struct ncplane* n, int* RESTRICT y, int* RESTRICT x);
void ncplane_dim_yx(struct ncplane* n, int* RESTRICT rows, int* RESTRICT cols);
static inline int
ncplane_dim_y(struct ncplane* n){
ncplane_dim_y(const struct ncplane* n){
int dimy;
ncplane_dim_yx(n, &dimy, NULL);
return dimy;
}
static inline int
ncplane_dim_x(struct ncplane* n){
ncplane_dim_x(const struct ncplane* n){
int dimx;
ncplane_dim_yx(n, NULL, &dimx);
return dimx;
@ -705,7 +706,7 @@ void ncplane_styles_on(struct ncplane* n, unsigned stylebits);
void ncplane_styles_off(struct ncplane* n, unsigned stylebits);
// Return the current styling for this ncplane.
unsigned ncplane_styles(struct ncplane* n);
unsigned ncplane_styles(const struct ncplane* n);
// Set the ncplane's base cell to this cell. It will be used for purposes of
// rendering anywhere that the ncplane's gcluster is 0. Erasing the ncplane

View File

@ -13,4 +13,6 @@ LICENSE=Apache-2.0
USE_GITHUB=yes
GH_ACCOUNT=dankamongmen
# deps: doxygen, dia, doctest (not present?), ffmpeg
.include <bsd.port.mk>

View File

@ -102,13 +102,17 @@ A few high-level widgets are included, all built atop ncplanes:
## Threads
Notcurses explicitly supports use in multithreaded environments. Most functions
are safe to call concurrently, with exceptions including those which destroy
resources (**ncplane_destroy(3)**, **ncvisual_destroy(3)**, **notcurses_stop(3)**,
etc.). Multiple threads interacting with the same ncplane will block one another,
but threads operating on distinct ncplanes can run concurrently.
**notcurses_render(3)** blocks the majority of functions. Input functions only
block other input functions, not ncplane manipulation.
Notcurses explicitly supports use in multithreaded environments, but it does
not itself perform any locking. It is safe to output to multiple distinct
ncplanes at the same time. It is safe to output to ncplanes while adding or
deleting some other ncplane. It is **not** safe for multiple threads to output to
the same ncplane. It is **not** safe to add, delete, or reorder ncplanes
from multiple threads, and it is never safe to invoke **notcurses_render**
while any other thread is touching that notcurses object (aside from input
functions; read on).
Only one thread may call **notcurses_getc** or any other input-related thread
at a time, but it **is** safe to call for input while another thread renders.
Since multiple threads can concurrently manipulate distinct ncplanes, peak
performance sometimes requires dividing the screen into several planes, and

View File

@ -112,6 +112,10 @@ Like any other notcurses function, it is an error to call **notcurses_getc(3)**
during or after a call to **notcurses_stop(3)**. If a thread is always sitting
on blocking input, it can be tricky to guarantee that this doesn't happen.
Only one thread may call into the input stack at once, but unlike almost every
other function in notcurses, **notcurses_getc** and friends can be called
concurrently with **notcurses_render**.
# BUGS
Failed escape sequences are not yet played back in their entirety; only an
@ -134,6 +138,7 @@ registers as **NCKEY_ENTER**. This will likely change in the future.
**poll(2)**,
**cfmakeraw(3)**,
**notcurses(3)**,
**notcurses_render(3)**,
**notcurses_resize(3)**,
**termios(3)**,
**terminfo(5)**,

View File

@ -48,11 +48,11 @@ notcurses_ncplane - operations on notcurses planes
**void* ncplane_userptr(struct ncplane* n);**
**void ncplane_dim_yx(struct ncplane* n, int* restrict rows, int* restrict cols);**
**void ncplane_dim_yx(const struct ncplane* n, int* restrict rows, int* restrict cols);**
**static inline int ncplane_dim_y(struct ncplane* n);**
**static inline int ncplane_dim_y(const struct ncplane* n);**
**static inline int ncplane_dim_x(struct ncplane* n);**
**static inline int ncplane_dim_x(const struct ncplane* n);**
**int ncplane_cursor_move_yx(struct ncplane* n, int y, int x);**
@ -108,7 +108,7 @@ notcurses_ncplane - operations on notcurses planes
**void ncplane_styles_off(struct ncplane* n, unsigned stylebits);**
**unsigned ncplane_styles(struct ncplane* n);**
**unsigned ncplane_styles(const struct ncplane* n);**
**void ncplane_greyscale(struct ncplane* n);**
@ -137,6 +137,10 @@ anywhere. In addition to its framebuffer--a rectilinear matrix of cells
**notcurses_drop_planes** destroys all ncplanes other than the stdplane. Any
references to such planes are, of course, invalidated.
It is an error for two threads to concurrently access a single ncplane. So long
as rendering is not taking place, however, multiple threads may safely output
to multiple ncplanes.
# RETURN VALUES
**ncplane_new(3)**, **ncplane_aligned(3)**, and **ncplane_dup(3)** all return a
@ -154,9 +158,6 @@ All other functions cannot fail (and return **void**).
# NOTES
It would be reasonable to expect many of these functions to accept `const struct notcurses`
parameters. Alas, almost all must manipulate the mutex contained within the object.
# SEE ALSO
**notcurses(3)**, **notcurses_cell(3)**, **notcurses_output(3)**,

View File

@ -23,17 +23,20 @@ ncplanes. Most of the notcurses statistics are updated as a result of a
render (see notcurses_stats(3)), and **notcurses_resize(3)** is called
internally *following* the render.
While **notcurses_render** is called, you **must not call any other functions
on the same notcurses context**, with the one exception of **notcurses_getc**
(and its input-related helpers).
A render operation consists of two logical phases: generation of the rendered
scene, and blitting this scene to the terminal (these two phases might actually
be interleaved, streaming the output as it is rendered). All ncplanes are
locked while generating the frame. Frame generation requires determining an
extended grapheme cluster, foreground color, background color, and style for
each cell of the physical terminal. Writing the scene requires synthesizing
a set of UTF-8-encoded characters and escape codes appropriate for the terminal
(relying on terminfo(5)), and writing this sequence to the output **FILE**. If
the **renderfp** value was not NULL in the original call to notcurses_init(3),
the frame will be written to that **FILE** as well. This write does not affect
statistics.
be interleaved, streaming the output as it is rendered). Frame generation
requires determining an extended grapheme cluster, foreground color, background
color, and style for each cell of the physical terminal. Writing the scene
requires synthesizing a set of UTF-8-encoded characters and escape codes
appropriate for the terminal (relying on terminfo(5)), and writing this
sequence to the output **FILE**. If the **renderfp** value was not NULL in the
original call to notcurses_init(3), the frame will be written to that **FILE**
as well. This write does not affect statistics.
Each cell can be rendered in isolation, though synthesis of the stream carries
dependencies between cells.

View File

@ -416,23 +416,24 @@ typedef struct ncstats {
} ncstats;
// Acquire an atomic snapshot of the notcurses object's stats.
API void notcurses_stats(struct notcurses* nc, ncstats* stats);
API void notcurses_stats(const struct notcurses* nc, ncstats* stats);
// Reset all cumulative stats (immediate ones, such as fbbytes, are not reset).
API void notcurses_reset_stats(struct notcurses* nc, ncstats* stats);
// Return the dimensions of this ncplane.
API void ncplane_dim_yx(struct ncplane* n, int* RESTRICT rows, int* RESTRICT cols);
API void ncplane_dim_yx(const struct ncplane* n, int* RESTRICT rows,
int* RESTRICT cols);
static inline int
ncplane_dim_y(struct ncplane* n){
ncplane_dim_y(const struct ncplane* n){
int dimy;
ncplane_dim_yx(n, &dimy, NULL);
return dimy;
}
static inline int
ncplane_dim_x(struct ncplane* n){
ncplane_dim_x(const struct ncplane* n){
int dimx;
ncplane_dim_yx(n, NULL, &dimx);
return dimx;
@ -550,7 +551,7 @@ API void* ncplane_userptr(struct ncplane* n);
// according to 'align' within ncplane 'n'. Returns INT_MAX on invalid 'align'.
// Undefined behavior on negative 'c'.
static inline int
ncplane_align(struct ncplane* n, ncalign_e align, int c){
ncplane_align(const struct ncplane* n, ncalign_e align, int c){
if(align == NCALIGN_LEFT){
return 0;
}
@ -907,7 +908,7 @@ channel_b(unsigned channel){
// Extract the three 8-bit R/G/B components from a 32-bit channel.
static inline unsigned
channel_rgb(unsigned channel, unsigned* RESTRICT r, unsigned* RESTRICT g,
unsigned* RESTRICT b){
unsigned* RESTRICT b){
*r = channel_r(channel);
*g = channel_g(channel);
*b = channel_b(channel);
@ -1495,7 +1496,7 @@ API void ncplane_styles_on(struct ncplane* n, unsigned stylebits);
API void ncplane_styles_off(struct ncplane* n, unsigned stylebits);
// Return the current styling for this ncplane.
API unsigned ncplane_styles(struct ncplane* n);
API unsigned ncplane_styles(const struct ncplane* n);
// Called for each delta performed in a fade on ncp. If anything but 0 is returned,
// the fading operation ceases immediately, and that value is propagated out. If provided

View File

@ -109,7 +109,7 @@ int ncplane_cursor_move_yx(struct ncplane* n, int y, int x);
void ncplane_cursor_yx(struct ncplane* n, int* y, int* x);
int ncplane_move_yx(struct ncplane* n, int y, int x);
void ncplane_yx(struct ncplane* n, int* y, int* x);
void ncplane_dim_yx(struct ncplane* n, int* rows, int* cols);
void ncplane_dim_yx(const struct ncplane* n, int* rows, int* cols);
int ncplane_putc_yx(struct ncplane* n, int y, int x, const cell* c);
int ncplane_putsimple_yx(struct ncplane* n, int y, int x, char c);
int ncplane_move_top(struct ncplane* n);
@ -149,7 +149,7 @@ int ncplane_set_bg_palindex(struct ncplane* n, int idx);
void ncplane_styles_set(struct ncplane* n, unsigned stylebits);
void ncplane_styles_on(struct ncplane* n, unsigned stylebits);
void ncplane_styles_off(struct ncplane* n, unsigned stylebits);
unsigned ncplane_styles(struct ncplane* n);
unsigned ncplane_styles(const struct ncplane* n);
typedef struct ncstats {
uint64_t renders; // number of successful notcurses_render() runs
uint64_t failed_renders; // number of aborted renders, should be 0

View File

@ -13,12 +13,10 @@ typedef struct planepalette {
// the maxima across each of the six components.
static int
alloc_ncplane_palette(ncplane* n, planepalette* pp){
ncplane_lock(n);
ncplane_dim_yx(n, &pp->rows, &pp->cols);
// add an additional element for the background cell
int size = pp->rows * pp->cols + 1;
if((pp->channels = malloc(sizeof(*pp->channels) * size)) == NULL){
ncplane_unlock(n);
return -1;
}
pp->maxr = pp->maxg = pp->maxb = 0;
@ -75,7 +73,6 @@ alloc_ncplane_palette(ncplane* n, planepalette* pp){
if(bb > pp->maxbb){
pp->maxbb = bb;
}
ncplane_unlock(n);
return 0;
}

View File

@ -209,7 +209,6 @@ typedef struct ncdirect {
} ncdirect;
typedef struct notcurses {
pthread_mutex_t lock;
ncplane* top; // the contents of our topmost plane (initially entire screen)
ncplane* stdscr;// aliases some plane from the z-buffer, covers screen
@ -318,16 +317,6 @@ void input_free_esctrie(struct esctrie** trie);
// initialize libav
int ncvisual_init(int loglevel);
static inline void
ncplane_lock(const ncplane* n){
pthread_mutex_lock(&n->nc->lock);
}
static inline void
ncplane_unlock(const ncplane* n){
pthread_mutex_unlock(&n->nc->lock);
}
static inline int
fbcellidx(int row, int rowlen, int col){
return row * rowlen + col;

View File

@ -191,8 +191,7 @@ int ncplane_at_cursor(ncplane* n, cell* c){
return cell_duplicate(n, c, &n->fb[nfbcellidx(n, n->y, n->x)]);
}
static inline int
ncplane_at_yx_locked(ncplane* n, int y, int x, cell* c){
int ncplane_at_yx(ncplane* n, int y, int x, cell* c){
int ret = -1;
if(y < n->leny && x < n->lenx){
if(y >= 0 && x >= 0){
@ -202,19 +201,11 @@ ncplane_at_yx_locked(ncplane* n, int y, int x, cell* c){
return ret;
}
int ncplane_at_yx(ncplane* n, int y, int x, cell* c){
int ret = -1;
pthread_mutex_lock(&n->nc->lock);
ret = ncplane_at_yx_locked(n, y, x, c);
pthread_mutex_unlock(&n->nc->lock);
return ret;
}
cell* ncplane_cell_ref_yx(ncplane* n, int y, int x){
return &n->fb[nfbcellidx(n, y, x)];
}
void ncplane_dim_yx(ncplane* n, int* rows, int* cols){
void ncplane_dim_yx(const ncplane* n, int* rows, int* cols){
if(rows){
*rows = n->leny;
}
@ -263,10 +254,8 @@ term_verify_seq(char** gseq, const char* name){
static void
free_plane(ncplane* p){
if(p){
ncplane_lock(p);
--p->nc->stats.planes;
p->nc->stats.fbbytes -= sizeof(*p->fb) * p->leny * p->lenx;
ncplane_unlock(p);
egcpool_dump(&p->pool);
free(p->fb);
free(p);
@ -300,13 +289,11 @@ ncplane_create(notcurses* nc, int rows, int cols, int yoff, int xoff){
p->channels = 0;
egcpool_init(&p->pool);
cell_init(&p->basecell);
pthread_mutex_lock(&nc->lock);
p->z = nc->top;
nc->top = p;
p->nc = nc;
nc->stats.fbbytes += fbsize;
++nc->stats.planes;
pthread_mutex_unlock(&nc->lock);
return p;
}
@ -741,17 +728,13 @@ stash_stats(notcurses* nc){
reset_stats(&nc->stats);
}
void notcurses_stats(notcurses* nc, ncstats* stats){
pthread_mutex_lock(&nc->lock);
void notcurses_stats(const notcurses* nc, ncstats* stats){
memcpy(stats, &nc->stats, sizeof(*stats));
pthread_mutex_unlock(&nc->lock);
}
void notcurses_reset_stats(notcurses* nc, ncstats* stats){
pthread_mutex_lock(&nc->lock);
memcpy(stats, &nc->stats, sizeof(*stats));
stash_stats(nc);
pthread_mutex_unlock(&nc->lock);
}
// Convert a notcurses log level to its ffmpeg equivalent.
@ -847,10 +830,6 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
if(ret == NULL){
return ret;
}
if(pthread_mutex_init(&ret->lock, NULL)){
free(ret);
return NULL;
}
ret->stats.fbbytes = 0;
ret->stashstats.fbbytes = 0;
reset_stats(&ret->stats);
@ -973,8 +952,8 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
return ret;
err:
// FIXME looks like we have some memory leaks on this error path?
tcsetattr(ret->ttyfd, TCSANOW, &ret->tpreserved);
pthread_mutex_destroy(&ret->lock);
free(ret);
return NULL;
}
@ -1033,7 +1012,6 @@ int notcurses_stop(notcurses* nc){
free(nc->lastframe);
free(nc->rstate.mstream);
input_free_esctrie(&nc->inputescapes);
ret |= pthread_mutex_destroy(&nc->lock);
stash_stats(nc);
if(!nc->suppress_banner){
double avg = 0;
@ -1098,21 +1076,15 @@ uint32_t ncplane_attr(const ncplane* n){
}
void ncplane_set_fg_default(struct ncplane* n){
ncplane_lock(n);
channels_set_fg_default(&n->channels);
ncplane_unlock(n);
}
void ncplane_set_bg_default(struct ncplane* n){
ncplane_lock(n);
channels_set_bg_default(&n->channels);
ncplane_unlock(n);
}
void ncplane_set_bg_rgb_clipped(ncplane* n, int r, int g, int b){
ncplane_lock(n);
channels_set_bg_rgb_clipped(&n->channels, r, g, b);
ncplane_unlock(n);
}
int ncplane_set_bg_rgb(ncplane* n, int r, int g, int b){
@ -1120,9 +1092,7 @@ int ncplane_set_bg_rgb(ncplane* n, int r, int g, int b){
}
void ncplane_set_fg_rgb_clipped(ncplane* n, int r, int g, int b){
ncplane_lock(n);
channels_set_fg_rgb_clipped(&n->channels, r, g, b);
ncplane_unlock(n);
}
int ncplane_set_fg_rgb(ncplane* n, int r, int g, int b){
@ -1130,48 +1100,30 @@ int ncplane_set_fg_rgb(ncplane* n, int r, int g, int b){
}
int ncplane_set_fg(ncplane* n, unsigned channel){
int ret;
ncplane_lock(n);
ret = channels_set_fg(&n->channels, channel);
ncplane_unlock(n);
return ret;
return channels_set_fg(&n->channels, channel);
}
int ncplane_set_bg(ncplane* n, unsigned channel){
int ret;
ncplane_lock(n);
ret = channels_set_bg(&n->channels, channel);
ncplane_unlock(n);
return ret;
return channels_set_bg(&n->channels, channel);
}
int ncplane_set_fg_alpha(ncplane* n, int alpha){
int ret;
ncplane_lock(n);
ret = channels_set_fg_alpha(&n->channels, alpha);
ncplane_unlock(n);
return ret;
return channels_set_fg_alpha(&n->channels, alpha);
}
int ncplane_set_bg_alpha(ncplane *n, int alpha){
int ret;
ncplane_lock(n);
ret = channels_set_bg_alpha(&n->channels, alpha);
ncplane_unlock(n);
return ret;
return channels_set_bg_alpha(&n->channels, alpha);
}
int ncplane_set_fg_palindex(ncplane* n, int idx){
if(idx < 0 || idx >= NCPALETTESIZE){
return -1;
}
ncplane_lock(n);
n->channels |= CELL_FGDEFAULT_MASK;
n->channels |= CELL_FG_PALETTE;
n->channels &= ~(CELL_ALPHA_MASK << 32u);
n->attrword &= 0xffff00ff;
n->attrword |= (idx << 8u);
ncplane_unlock(n);
return 0;
}
@ -1179,40 +1131,24 @@ int ncplane_set_bg_palindex(ncplane* n, int idx){
if(idx < 0 || idx >= NCPALETTESIZE){
return -1;
}
ncplane_lock(n);
n->channels |= CELL_BGDEFAULT_MASK;
n->channels |= CELL_BG_PALETTE;
n->channels &= ~CELL_ALPHA_MASK;
n->attrword &= 0xffffff00;
n->attrword |= idx;
ncplane_unlock(n);
return 0;
}
int ncplane_set_base_cell(ncplane* ncp, const cell* c){
ncplane_lock(ncp);
int ret = cell_duplicate(ncp, &ncp->basecell, c);
ncplane_unlock(ncp);
if(ret < 0){
return -1;
}
return ret;
return cell_duplicate(ncp, &ncp->basecell, c);
}
int ncplane_set_base(ncplane* ncp, uint64_t channels, uint32_t attrword, const char* egc){
int ret;
ncplane_lock(ncp);
ret = cell_prime(ncp, &ncp->basecell, egc, attrword, channels);
ncplane_unlock(ncp);
return ret;
return cell_prime(ncp, &ncp->basecell, egc, attrword, channels);
}
int ncplane_base(ncplane* ncp, cell* c){
int ret;
ncplane_lock(ncp);
ret = cell_duplicate(ncp, c, &ncp->basecell);
ncplane_unlock(ncp);
return ret;
return cell_duplicate(ncp, c, &ncp->basecell);
}
const char* cell_extended_gcluster(const struct ncplane* n, const cell* c){
@ -1232,66 +1168,52 @@ advance_cursor(ncplane* n, int cols){
// 'n' ends up above 'above'
int ncplane_move_above_unsafe(ncplane* restrict n, ncplane* restrict above){
ncplane_lock(n);
if(n->z == above){
ncplane_unlock(n);
return 0;
}
ncplane** an = find_above_ncplane(n);
if(an == NULL){
ncplane_unlock(n);
return -1;
}
ncplane** aa = find_above_ncplane(above);
if(aa == NULL){
ncplane_unlock(n);
return -1;
}
*an = n->z; // splice n out
n->z = above; // attach above below n
*aa = n; // spline n in above
ncplane_unlock(n);
return 0;
}
// 'n' ends up below 'below'
int ncplane_move_below_unsafe(ncplane* restrict n, ncplane* restrict below){
ncplane_lock(n);
if(below->z == n){
ncplane_unlock(n);
return 0;
}
ncplane** an = find_above_ncplane(n);
if(an == NULL){
ncplane_unlock(n);
return -1;
}
*an = n->z; // splice n out
n->z = below->z; // reattach subbelow list to n
below->z = n; // splice n in below
ncplane_unlock(n);
return 0;
}
int ncplane_move_top(ncplane* n){
ncplane_lock(n);
ncplane** an = find_above_ncplane(n);
if(an == NULL){
ncplane_unlock(n);
return -1;
}
*an = n->z; // splice n out
n->z = n->nc->top;
n->nc->top = n;
ncplane_unlock(n);
return 0;
}
int ncplane_move_bottom(ncplane* n){
ncplane_lock(n);
ncplane** an = find_above_ncplane(n);
if(an == NULL){
ncplane_unlock(n);
return -1;
}
*an = n->z; // splice n out
@ -1301,15 +1223,11 @@ int ncplane_move_bottom(ncplane* n){
}
*an = n;
n->z = NULL;
ncplane_unlock(n);
return 0;
}
int ncplane_cursor_move_yx(ncplane* n, int y, int x){
ncplane_lock(n);
int ret = ncplane_cursor_move_yx_locked(n, y, x);
ncplane_unlock(n);
return ret;
return ncplane_cursor_move_yx_locked(n, y, x);
}
void ncplane_cursor_yx(ncplane* n, int* y, int* x){
@ -1333,14 +1251,11 @@ cell_obliterate(ncplane* n, cell* c){
}
int ncplane_putc_yx(ncplane* n, int y, int x, const cell* c){
ncplane_lock(n);
if(ncplane_cursor_move_yx_locked(n, y, x)){
ncplane_unlock(n);
return -1;
}
bool wide = cell_double_wide_p(c);
if(wide && (n->x + 1 == n->lenx)){
ncplane_unlock(n);
return -1;
}
// A wide character obliterates anything to its immediate right (and marks
@ -1358,7 +1273,6 @@ int ncplane_putc_yx(ncplane* n, int y, int x, const cell* c){
}
}
if(cell_duplicate(n, targ, c) < 0){
ncplane_unlock(n);
return -1;
}
int cols = 1;
@ -1382,7 +1296,6 @@ int ncplane_putc_yx(ncplane* n, int y, int x, const cell* c){
}
}
advance_cursor(n, cols);
ncplane_unlock(n);
return cols;
}
@ -1492,31 +1405,21 @@ int notcurses_palette_size(const notcurses* nc){
// turn on any specified stylebits
void ncplane_styles_on(ncplane* n, unsigned stylebits){
ncplane_lock(n);
n->attrword |= (stylebits & NCSTYLE_MASK);
ncplane_unlock(n);
}
// turn off any specified stylebits
void ncplane_styles_off(ncplane* n, unsigned stylebits){
ncplane_lock(n);
n->attrword &= ~(stylebits & NCSTYLE_MASK);
ncplane_unlock(n);
}
// set the current stylebits to exactly those provided
void ncplane_styles_set(ncplane* n, unsigned stylebits){
ncplane_lock(n);
n->attrword = (n->attrword & ~NCSTYLE_MASK) | ((stylebits & NCSTYLE_MASK));
ncplane_unlock(n);
}
unsigned ncplane_styles(ncplane* n){
unsigned ret;
ncplane_lock(n);
ret = (n->attrword & NCSTYLE_MASK);
ncplane_unlock(n);
return ret;
unsigned ncplane_styles(const ncplane* n){
return (n->attrword & NCSTYLE_MASK);
}
// i hate the big allocation and two copies here, but eh what you gonna do?
@ -1807,30 +1710,24 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
}
int ncplane_move_yx(ncplane* n, int y, int x){
ncplane_lock(n);
if(n == n->nc->stdscr){
ncplane_unlock(n);
return -1;
}
n->absy = y;
n->absx = x;
ncplane_unlock(n);
return 0;
}
void ncplane_yx(const ncplane* n, int* y, int* x){
ncplane_lock(n);
if(y){
*y = n->absy;
}
if(x){
*x = n->absx;
}
ncplane_unlock(n);
}
void ncplane_erase(ncplane* n){
ncplane_lock(n);
// we must preserve the background, but a pure cell_duplicate() would be
// wiped out by the egcpool_dump(). do a duplication (to get the attrword
// and channels), and then reload.
@ -1840,7 +1737,6 @@ void ncplane_erase(ncplane* n){
egcpool_init(&n->pool);
cell_load(n, &n->basecell, egc);
free(egc);
ncplane_unlock(n);
}
void notcurses_cursor_enable(notcurses* nc){
@ -1891,11 +1787,9 @@ bool notcurses_canchangecolor(const notcurses* nc){
palette256* palette256_new(notcurses* nc){
palette256* p = malloc(sizeof(*p));
pthread_mutex_lock(&nc->lock);
if(p){
memcpy(p, &nc->palette, sizeof(*p));
}
pthread_mutex_unlock(&nc->lock);
return p;
}
@ -1904,7 +1798,6 @@ int palette256_use(notcurses* nc, const palette256* p){
if(!nc->CCCflag){
return -1;
}
pthread_mutex_lock(&nc->lock);
for(size_t z = 0 ; z < sizeof(p->chans) / sizeof(*p->chans) ; ++z){
if(nc->palette.chans[z] != p->chans[z]){
nc->palette.chans[z] = p->chans[z];
@ -1912,7 +1805,6 @@ int palette256_use(notcurses* nc, const palette256* p){
}
}
ret = 0;
pthread_mutex_unlock(&nc->lock);
return ret;
}
@ -1940,7 +1832,6 @@ rgb_greyscale(int r, int g, int b){
}
void ncplane_greyscale(ncplane *n){
ncplane_lock(n);
for(int y = 0 ; y < n->leny ; ++y){
for(int x = 0 ; x < n->lenx ; ++x){
cell* c = &n->fb[nfbcellidx(n, y, x)];
@ -1953,7 +1844,6 @@ void ncplane_greyscale(ncplane *n){
cell_set_bg_rgb(c, gy, gy, gy);
}
}
ncplane_unlock(n);
}
// if this is not polyfillable cell, we return 0. if it is, we attempt to fill
@ -1998,13 +1888,11 @@ ncplane_polyfill_locked(ncplane* n, int y, int x, const cell* c){
// at the initial step only, invalid y, x is an error, so explicitly check.
int ncplane_polyfill_yx(ncplane* n, int y, int x, const cell* c){
int ret = -1;
ncplane_lock(n);
if(y < n->leny && x < n->lenx){
if(y >= 0 && x >= 0){
ret = ncplane_polyfill_locked(n, y, x, c);
}
}
ncplane_unlock(n);
return ret;
}

View File

@ -4,11 +4,6 @@
#include <sys/poll.h>
#include "internal.h"
static void
mutex_unlock(void* vlock){
pthread_mutex_unlock(vlock);
}
static int
blocking_write(int fd, const char* buf, size_t buflen){
//fprintf(stderr, "writing %zu to %d...\n", buflen, fd);
@ -36,8 +31,6 @@ blocking_write(int fd, const char* buf, size_t buflen){
int notcurses_refresh(notcurses* nc){
int ret;
pthread_mutex_lock(&nc->lock);
pthread_cleanup_push(mutex_unlock, &nc->lock);
if(nc->rstate.mstream == NULL){
ret = -1; // haven't rendered yet, and thus don't know what should be there
}else if(blocking_write(nc->ttyfd, nc->rstate.mstream, nc->rstate.mstrsize)){
@ -45,7 +38,6 @@ int notcurses_refresh(notcurses* nc){
}else{
ret = 0;
}
pthread_cleanup_pop(1);
return ret;
}
@ -962,8 +954,6 @@ int notcurses_render(notcurses* nc){
struct timespec start, done;
int ret;
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
pthread_mutex_lock(&nc->lock);
pthread_cleanup_push(mutex_unlock, &nc->lock);
int bytes = -1;
size_t crenderlen = sizeof(struct crender) * nc->stdscr->leny * nc->stdscr->lenx;
struct crender* crender = malloc(crenderlen);
@ -977,13 +967,11 @@ int notcurses_render(notcurses* nc){
clock_gettime(CLOCK_MONOTONIC_RAW, &done);
update_render_stats(&done, &start, &nc->stats, bytes);
ret = bytes >= 0 ? 0 : -1;
pthread_cleanup_pop(1);
return ret;
}
char* notcurses_at_yx(notcurses* nc, int y, int x, cell* c){
char* egc = NULL;
pthread_mutex_lock(&nc->lock);
if(nc->lastframe){
if(y >= 0 && y < nc->lfdimy){
if(x >= 0 || x < nc->lfdimx){
@ -995,6 +983,5 @@ char* notcurses_at_yx(notcurses* nc, int y, int x, cell* c){
}
}
}
pthread_mutex_unlock(&nc->lock);
return egc;
}