kopia lustrzana https://gitlab.com/sane-project/backends
Use sanei_thread instead of fork() in the unmaintained backends.
Patches from Mattias Ellert (bugs: 300635, 300634, 300633, 300629).merge-requests/1/head
rodzic
04e08cc9ef
commit
07d7013992
|
@ -2,6 +2,11 @@
|
|||
|
||||
* tools/check-usb-scanner.c: Detect GL660+GL646 on USB2 also.
|
||||
Fixed Mustek MA1017 scanner freeze problem.
|
||||
* backend/Makefile.in backend/agfafocus.c backend/agfafocus.h
|
||||
backend/microtek2.c backend/microtek2.h backend/sp15c.c
|
||||
backend/sp15c.h backend/tamarack.c backend/tamarack.h:
|
||||
Use sanei_thread instead of fork() in the unmaintained backends.
|
||||
Patches from Mattias Ellert (bugs: 300635, 300634, 300633, 300629).
|
||||
|
||||
2004-05-21 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
|
||||
|
|
|
@ -269,6 +269,7 @@ libsane-abaton.la: ../sanei/sanei_scsi.lo
|
|||
libsane-agfafocus.la: ../sanei/sanei_config2.lo
|
||||
libsane-agfafocus.la: ../sanei/sanei_constrain_value.lo
|
||||
libsane-agfafocus.la: ../sanei/sanei_scsi.lo
|
||||
libsane-agfafocus.la: ../sanei/sanei_thread.lo
|
||||
libsane-apple.la: ../sanei/sanei_config2.lo
|
||||
libsane-apple.la: ../sanei/sanei_constrain_value.lo
|
||||
libsane-apple.la: ../sanei/sanei_scsi.lo
|
||||
|
@ -344,6 +345,7 @@ libsane-microtek.la: ../sanei/sanei_scsi.lo
|
|||
libsane-microtek2.la: ../sanei/sanei_config2.lo
|
||||
libsane-microtek2.la: ../sanei/sanei_constrain_value.lo
|
||||
libsane-microtek2.la: ../sanei/sanei_scsi.lo
|
||||
libsane-microtek2.la: ../sanei/sanei_thread.lo
|
||||
libsane-mustek.la: ../sanei/sanei_config2.lo
|
||||
libsane-mustek.la: ../sanei/sanei_constrain_value.lo
|
||||
libsane-mustek.la: ../sanei/sanei_scsi.lo
|
||||
|
@ -395,12 +397,14 @@ libsane-snapscan.la: ../sanei/sanei_thread.lo
|
|||
libsane-sp15c.la: ../sanei/sanei_config2.lo
|
||||
libsane-sp15c.la: ../sanei/sanei_constrain_value.lo
|
||||
libsane-sp15c.la: ../sanei/sanei_scsi.lo
|
||||
libsane-sp15c.la: ../sanei/sanei_thread.lo
|
||||
libsane-st400.la: ../sanei/sanei_config2.lo
|
||||
libsane-st400.la: ../sanei/sanei_constrain_value.lo
|
||||
libsane-st400.la: ../sanei/sanei_scsi.lo
|
||||
libsane-tamarack.la: ../sanei/sanei_config2.lo
|
||||
libsane-tamarack.la: ../sanei/sanei_constrain_value.lo
|
||||
libsane-tamarack.la: ../sanei/sanei_scsi.lo
|
||||
libsane-tamarack.la: ../sanei/sanei_thread.lo
|
||||
libsane-test.la: ../sanei/sanei_constrain_value.lo
|
||||
libsane-test.la: ../sanei/sanei_thread.lo
|
||||
libsane-teco1.la: ../sanei/sanei_config2.lo
|
||||
|
|
|
@ -30,13 +30,13 @@
|
|||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "sane/sane.h"
|
||||
#include "sane/sanei.h"
|
||||
#include "sane/sanei_config.h"
|
||||
#include "sane/saneopts.h"
|
||||
#include "sane/sanei_scsi.h"
|
||||
#include "sane/sanei_thread.h"
|
||||
|
||||
#define BACKEND_NAME agfafocus
|
||||
#include "sane/sanei_backend.h"
|
||||
|
@ -952,8 +952,8 @@ do_cancel (AgfaFocus_Scanner * s)
|
|||
int exit_status;
|
||||
|
||||
/* ensure child knows it's time to stop: */
|
||||
kill (s->reader_pid, SIGTERM);
|
||||
while (wait (&exit_status) != s->reader_pid);
|
||||
sanei_thread_kill (s->reader_pid);
|
||||
sanei_thread_waitpid (s->reader_pid, &exit_status);
|
||||
s->reader_pid = 0;
|
||||
}
|
||||
|
||||
|
@ -1283,6 +1283,8 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
|||
|
||||
DBG_INIT ();
|
||||
|
||||
sanei_thread_init ();
|
||||
|
||||
if (version_code)
|
||||
*version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 0);
|
||||
|
||||
|
@ -1775,8 +1777,11 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
|
|||
to update any of the variables in the main process (in particular
|
||||
the scanner state cannot be updated). */
|
||||
static int
|
||||
reader_process (AgfaFocus_Scanner * s, int fd)
|
||||
reader_process (void *scanner)
|
||||
{
|
||||
AgfaFocus_Scanner *s = (AgfaFocus_Scanner *) scanner;
|
||||
int fd = s->reader_pipe;
|
||||
|
||||
SANE_Status status;
|
||||
SANE_Byte *data;
|
||||
int lines_read = 0;
|
||||
|
@ -1784,6 +1789,17 @@ reader_process (AgfaFocus_Scanner * s, int fd)
|
|||
int bytes_per_line = 0, total_lines = 0;
|
||||
int i;
|
||||
sigset_t sigterm_set;
|
||||
sigset_t ignore_set;
|
||||
struct SIGACTION act;
|
||||
|
||||
if (sanei_thread_is_forked()) close (s->pipe);
|
||||
|
||||
sigfillset (&ignore_set);
|
||||
sigdelset (&ignore_set, SIGTERM);
|
||||
sigprocmask (SIG_SETMASK, &ignore_set, 0);
|
||||
|
||||
memset (&act, 0, sizeof (act));
|
||||
sigaction (SIGTERM, &act, 0);
|
||||
|
||||
sigemptyset (&sigterm_set);
|
||||
sigaddset (&sigterm_set, SIGTERM);
|
||||
|
@ -1985,25 +2001,11 @@ sane_start (SANE_Handle handle)
|
|||
if (pipe (fds) < 0)
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
|
||||
s->reader_pid = fork ();
|
||||
if (s->reader_pid == 0) {
|
||||
sigset_t ignore_set;
|
||||
struct SIGACTION act;
|
||||
|
||||
close (fds[0]);
|
||||
|
||||
sigfillset (&ignore_set);
|
||||
sigdelset (&ignore_set, SIGTERM);
|
||||
sigprocmask (SIG_SETMASK, &ignore_set, 0);
|
||||
|
||||
memset (&act, 0, sizeof (act));
|
||||
sigaction (SIGTERM, &act, 0);
|
||||
|
||||
/* don't use exit() since that would run the atexit() handlers... */
|
||||
_exit (reader_process (s, fds[1]));
|
||||
}
|
||||
close (fds[1]);
|
||||
s->pipe = fds[0];
|
||||
s->reader_pipe = fds[1];
|
||||
s->reader_pid = sanei_thread_begin (reader_process, (void *) s);
|
||||
|
||||
if (sanei_thread_is_forked()) close (s->reader_pipe);
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
@ -2047,7 +2049,7 @@ sane_cancel (SANE_Handle handle)
|
|||
AgfaFocus_Scanner *s = handle;
|
||||
|
||||
if (s->reader_pid > 0)
|
||||
kill (s->reader_pid, SIGTERM);
|
||||
sanei_thread_kill (s->reader_pid);
|
||||
s->scanning = SANE_FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ typedef struct AgfaFocus_Scanner
|
|||
int fd; /* SCSI filedescriptor */
|
||||
pid_t reader_pid; /* process id of reader */
|
||||
int pipe; /* pipe to reader process */
|
||||
int reader_pipe; /* pipe from reader process */
|
||||
|
||||
/* scanner dependent/low-level state: */
|
||||
AgfaFocus_Device *hw;
|
||||
|
|
|
@ -68,7 +68,6 @@
|
|||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
@ -83,10 +82,7 @@
|
|||
#include "../include/sane/sanei_config.h"
|
||||
#include "../include/sane/sanei_scsi.h"
|
||||
#include "../include/sane/saneopts.h"
|
||||
|
||||
#ifdef HAVE_OS2_H
|
||||
#include "../include/sane/sanei_thread.h"
|
||||
#endif
|
||||
|
||||
#ifndef TESTBACKEND
|
||||
#define BACKEND_NAME microtek2
|
||||
|
@ -467,6 +463,8 @@ sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize)
|
|||
trash = authorize; /* prevents compiler warning "unused variable" */
|
||||
#endif
|
||||
|
||||
sanei_thread_init();
|
||||
|
||||
match = 0;
|
||||
fp = sanei_config_open(MICROTEK2_CONFIG_FILE);
|
||||
if ( fp == NULL )
|
||||
|
@ -912,8 +910,8 @@ cancel_scan(Microtek2_Scanner *ms)
|
|||
likely what we really want - --mj, 2001/Nov/19 */
|
||||
if (ms->pid > 1)
|
||||
{
|
||||
kill(ms->pid, SIGTERM);
|
||||
waitpid(ms->pid, NULL, 0);
|
||||
sanei_thread_kill(ms->pid);
|
||||
sanei_thread_waitpid(ms->pid, NULL);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -5465,11 +5463,7 @@ sane_start(SANE_Handle handle)
|
|||
}
|
||||
|
||||
/* create reader routine as new thread or process */
|
||||
#ifdef HAVE_OS2_H
|
||||
ms->pid = sanei_thread_begin( reader_process,(void*) ms);
|
||||
#else
|
||||
ms->pid = fork();
|
||||
#endif
|
||||
|
||||
if ( ms->pid == -1 )
|
||||
{
|
||||
|
@ -5477,12 +5471,9 @@ sane_start(SANE_Handle handle)
|
|||
status = SANE_STATUS_IO_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
else if ( ms->pid == 0 ) /* child process */
|
||||
_exit(reader_process(ms));
|
||||
|
||||
#ifndef HAVE_OS2_H
|
||||
close(ms->fd[1]);
|
||||
#endif
|
||||
if (sanei_thread_is_forked()) close(ms->fd[1]);
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
|
||||
cleanup:
|
||||
|
@ -7099,9 +7090,11 @@ set_exposure(Microtek2_Scanner *ms)
|
|||
|
||||
/*---------- reader_process() ------------------------------------------------*/
|
||||
|
||||
static SANE_Status
|
||||
reader_process(Microtek2_Scanner *ms)
|
||||
static int
|
||||
reader_process(void *data)
|
||||
{
|
||||
Microtek2_Scanner *ms = (Microtek2_Scanner *) data;
|
||||
|
||||
SANE_Status status;
|
||||
Microtek2_Info *mi;
|
||||
Microtek2_Device *md;
|
||||
|
@ -7113,9 +7106,9 @@ reader_process(Microtek2_Scanner *ms)
|
|||
|
||||
md = ms->dev;
|
||||
mi = &md->info[md->scan_source];
|
||||
#ifndef HAVE_OS2_H
|
||||
close(ms->fd[0]);
|
||||
#endif
|
||||
|
||||
if (sanei_thread_is_forked()) close(ms->fd[0]);
|
||||
|
||||
sigemptyset (&sigterm_set);
|
||||
sigaddset (&sigterm_set, SIGTERM);
|
||||
memset (&act, 0, sizeof (act));
|
||||
|
|
|
@ -1287,8 +1287,8 @@ read_cx_shading_image(Microtek2_Scanner *);
|
|||
static SANE_Status
|
||||
read_cx_shading(Microtek2_Scanner *);
|
||||
|
||||
static SANE_Status
|
||||
reader_process(Microtek2_Scanner *);
|
||||
static int
|
||||
reader_process(void *);
|
||||
|
||||
static SANE_Status
|
||||
restore_gamma_options(SANE_Option_Descriptor *, Option_Value *);
|
||||
|
|
|
@ -45,6 +45,10 @@ static const char RCSid[] = "$Header$";
|
|||
|
||||
/*
|
||||
* $Log$
|
||||
* Revision 1.6 2004/05/23 17:28:56 hmg-guest
|
||||
* Use sanei_thread instead of fork() in the unmaintained backends.
|
||||
* Patches from Mattias Ellert (bugs: 300635, 300634, 300633, 300629).
|
||||
*
|
||||
* Revision 1.5 2003/12/27 17:48:38 hmg-guest
|
||||
* Silenced some compilation warnings.
|
||||
*
|
||||
|
@ -176,14 +180,13 @@ static const char RCSid[] = "$Header$";
|
|||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sane/sanei_backend.h"
|
||||
#include "sane/sanei_scsi.h"
|
||||
#include "sane/saneopts.h"
|
||||
#include "sane/sanei_config.h"
|
||||
|
||||
#include "sane/sanei_thread.h"
|
||||
|
||||
#include "sp15c-scsi.h"
|
||||
#include "sp15c.h"
|
||||
|
@ -241,6 +244,8 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
|||
DBG_INIT ();
|
||||
DBG (10, "sane_init\n");
|
||||
|
||||
sanei_thread_init ();
|
||||
|
||||
if (version_code)
|
||||
*version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 0);
|
||||
fp = sanei_config_open (SP15C_CONFIG_FILE);
|
||||
|
@ -819,27 +824,11 @@ sane_start (SANE_Handle handle)
|
|||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
scanner->reader_pid = fork ();
|
||||
if (scanner->reader_pid == 0)
|
||||
{
|
||||
/* reader_pid = 0 ===> child process */
|
||||
sigset_t ignore_set;
|
||||
struct SIGACTION act;
|
||||
|
||||
close (fds[0]);
|
||||
|
||||
sigfillset (&ignore_set);
|
||||
sigdelset (&ignore_set, SIGTERM);
|
||||
sigprocmask (SIG_SETMASK, &ignore_set, 0);
|
||||
|
||||
memset (&act, 0, sizeof (act));
|
||||
sigaction (SIGTERM, &act, 0);
|
||||
|
||||
/* don't use exit() since that would run the atexit() handlers... */
|
||||
_exit (reader_process (scanner, fds[1]));
|
||||
}
|
||||
close (fds[1]);
|
||||
scanner->pipe = fds[0];
|
||||
scanner->reader_pipe = fds[1];
|
||||
scanner->reader_pid = sanei_thread_begin (reader_process, (void *) scanner);
|
||||
|
||||
close (scanner->reader_pipe);
|
||||
|
||||
DBG (10, "sane_start: ok\n");
|
||||
return SANE_STATUS_GOOD;
|
||||
|
@ -1733,10 +1722,9 @@ do_cancel (struct sp15c *scanner)
|
|||
int exit_status;
|
||||
DBG (10, "do_cancel: kill reader_process\n");
|
||||
/* ensure child knows it's time to stop: */
|
||||
kill (scanner->reader_pid, SIGTERM);
|
||||
while (wait (&exit_status) != scanner->reader_pid)
|
||||
sanei_thread_kill (scanner->reader_pid);
|
||||
DBG (50, "wait for scanner to stop\n");
|
||||
;
|
||||
sanei_thread_waitpid (scanner->reader_pid, &exit_status);
|
||||
scanner->reader_pid = 0;
|
||||
}
|
||||
|
||||
|
@ -1929,12 +1917,16 @@ sigterm_handler (int signal)
|
|||
|
||||
/* This function is executed as a child process. */
|
||||
static int
|
||||
reader_process (struct sp15c *scanner, int pipe_fd)
|
||||
reader_process (void *data)
|
||||
{
|
||||
struct sp15c *scanner = (struct sp15c *) data;
|
||||
int pipe_fd = scanner->reader_pipe;
|
||||
|
||||
int status;
|
||||
unsigned int data_left;
|
||||
unsigned int data_to_read;
|
||||
FILE *fp;
|
||||
sigset_t ignore_set;
|
||||
sigset_t sigterm_set;
|
||||
struct SIGACTION act;
|
||||
unsigned int i;
|
||||
|
@ -1942,6 +1934,15 @@ reader_process (struct sp15c *scanner, int pipe_fd)
|
|||
|
||||
DBG (10, "reader_process started\n");
|
||||
|
||||
if (sanei_thread_is_forked) close (scanner->pipe);
|
||||
|
||||
sigfillset (&ignore_set);
|
||||
sigdelset (&ignore_set, SIGTERM);
|
||||
sigprocmask (SIG_SETMASK, &ignore_set, 0);
|
||||
|
||||
memset (&act, 0, sizeof (act));
|
||||
sigaction (SIGTERM, &act, 0);
|
||||
|
||||
sigemptyset (&sigterm_set);
|
||||
sigaddset (&sigterm_set, SIGTERM);
|
||||
|
||||
|
|
|
@ -49,6 +49,10 @@ static const char RCSid_h[] = "$Header$";
|
|||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
* $Log$
|
||||
* Revision 1.5 2004/05/23 17:28:56 hmg-guest
|
||||
* Use sanei_thread instead of fork() in the unmaintained backends.
|
||||
* Patches from Mattias Ellert (bugs: 300635, 300634, 300633, 300629).
|
||||
*
|
||||
* Revision 1.4 2003/12/27 17:48:38 hmg-guest
|
||||
* Silenced some compilation warnings.
|
||||
*
|
||||
|
@ -132,6 +136,7 @@ struct sp15c
|
|||
char *devicename; /* name of the scanner device */
|
||||
int sfd; /* output file descriptor, scanner device */
|
||||
int pipe;
|
||||
int reader_pipe;
|
||||
|
||||
int scanning; /* "in progress" flag */
|
||||
int autofeeder; /* detected */
|
||||
|
@ -287,7 +292,7 @@ static int
|
|||
sp15c_start_scan (struct sp15c *s);
|
||||
|
||||
static int
|
||||
reader_process (struct sp15c *scanner, int pipe_fd);
|
||||
reader_process (void *scanner);
|
||||
|
||||
static SANE_Status
|
||||
do_eof (struct sp15c *scanner);
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
|
@ -55,6 +54,7 @@
|
|||
#include "sane/sanei.h"
|
||||
#include "sane/saneopts.h"
|
||||
#include "sane/sanei_scsi.h"
|
||||
#include "sane/sanei_thread.h"
|
||||
#include "sane/sanei_config.h"
|
||||
|
||||
/* For timeval... */
|
||||
|
@ -470,8 +470,8 @@ do_cancel (Tamarack_Scanner *s)
|
|||
int exit_status;
|
||||
|
||||
/* ensure child knows it's time to stop: */
|
||||
kill (s->reader_pid, SIGTERM);
|
||||
while (wait (&exit_status) != s->reader_pid);
|
||||
sanei_thread_kill (s->reader_pid);
|
||||
sanei_thread_waitpid (s->reader_pid, &exit_status);
|
||||
s->reader_pid = 0;
|
||||
}
|
||||
|
||||
|
@ -811,14 +811,28 @@ init_options (Tamarack_Scanner *s)
|
|||
to update any of the variables in the main process (in particular
|
||||
the scanner state cannot be updated). */
|
||||
static int
|
||||
reader_process (Tamarack_Scanner *s, int fd)
|
||||
reader_process (void *scanner)
|
||||
{
|
||||
Tamarack_Scanner *s = (Tamarack_Scanner *) scanner;
|
||||
int fd = s->reader_pipe;
|
||||
|
||||
SANE_Byte *data;
|
||||
int lines_per_buffer, bpl;
|
||||
SANE_Status status;
|
||||
sigset_t sigterm_set;
|
||||
sigset_t ignore_set;
|
||||
struct SIGACTION act;
|
||||
FILE *fp;
|
||||
|
||||
if (sanei_thread_is_forked()) close (s->pipe);
|
||||
|
||||
sigfillset (&ignore_set);
|
||||
sigdelset (&ignore_set, SIGTERM);
|
||||
sigprocmask (SIG_SETMASK, &ignore_set, 0);
|
||||
|
||||
memset (&act, 0, sizeof (act));
|
||||
sigaction (SIGTERM, &act, 0);
|
||||
|
||||
sigemptyset (&sigterm_set);
|
||||
sigaddset (&sigterm_set, SIGTERM);
|
||||
|
||||
|
@ -890,6 +904,8 @@ sane_init (SANE_Int *version_code, SANE_Auth_Callback authorize)
|
|||
|
||||
DBG_INIT();
|
||||
|
||||
sanei_thread_init();
|
||||
|
||||
if (version_code)
|
||||
*version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 0);
|
||||
|
||||
|
@ -1363,25 +1379,11 @@ sane_start (SANE_Handle handle)
|
|||
if (pipe (fds) < 0)
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
|
||||
s->reader_pid = fork ();
|
||||
if (s->reader_pid == 0) {
|
||||
sigset_t ignore_set;
|
||||
struct SIGACTION act;
|
||||
|
||||
close (fds[0]);
|
||||
|
||||
sigfillset (&ignore_set);
|
||||
sigdelset (&ignore_set, SIGTERM);
|
||||
sigprocmask (SIG_SETMASK, &ignore_set, 0);
|
||||
|
||||
memset (&act, 0, sizeof (act));
|
||||
sigaction (SIGTERM, &act, 0);
|
||||
|
||||
/* don't use exit() since that would run the atexit() handlers... */
|
||||
_exit (reader_process (s, fds[1]));
|
||||
}
|
||||
close (fds[1]);
|
||||
s->pipe = fds[0];
|
||||
s->reader_pipe = fds[1];
|
||||
s->reader_pid = sanei_thread_begin (reader_process, (void *) s);
|
||||
|
||||
if (sanei_thread_is_forked()) close (s->reader_pipe);
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
|
||||
|
@ -1430,7 +1432,7 @@ sane_cancel (SANE_Handle handle)
|
|||
Tamarack_Scanner *s = handle;
|
||||
|
||||
if (s->reader_pid > 0)
|
||||
kill (s->reader_pid, SIGTERM);
|
||||
sanei_thread_kill (s->reader_pid);
|
||||
s->scanning = SANE_FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@ typedef struct Tamarack_Scanner
|
|||
int fd; /* SCSI filedescriptor */
|
||||
pid_t reader_pid; /* process id of reader */
|
||||
int pipe; /* pipe to reader process */
|
||||
int reader_pipe; /* pipe from reader process */
|
||||
|
||||
/* scanner dependent/low-level state: */
|
||||
Tamarack_Device *hw;
|
||||
|
|
Ładowanie…
Reference in New Issue