mirror of https://github.com/xemu-project/xemu.git
Merge remote-tracking branch 'stefanha/trivial-patches' into staging
# By liguang (2) and others # Via Stefan Hajnoczi * stefanha/trivial-patches: qdev: remove redundant abort() gitignore: ignore more files Use proper term in TCG README serial: Fix debug format strings Fix typos and misspellings Advertise --libdir in configure --help output memory: fix a bug of detection of memory region collision MinGW: Replace setsockopt by qemu_setsocketopt
This commit is contained in:
commit
cecd77ae6d
|
@ -80,6 +80,9 @@ fsdev/virtfs-proxy-helper.pod
|
|||
*.swp
|
||||
*.orig
|
||||
.pc
|
||||
*.patch
|
||||
*.gcda
|
||||
*.gcno
|
||||
patches
|
||||
pc-bios/bios-pq/status
|
||||
pc-bios/vgabios-pq/status
|
||||
|
|
|
@ -171,7 +171,7 @@ struct HCIInfo *bt_host_hci(const char *id)
|
|||
hci_filter_all_ptypes(&flt);
|
||||
hci_filter_all_events(&flt);
|
||||
|
||||
if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
|
||||
if (qemu_setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
|
||||
fprintf(stderr, "qemu: Can't set HCI filter on socket (%i)\n", errno);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1050,6 +1050,7 @@ echo " --mandir=PATH install man pages in PATH"
|
|||
echo " --datadir=PATH install firmware in PATH$confsuffix"
|
||||
echo " --docdir=PATH install documentation in PATH$confsuffix"
|
||||
echo " --bindir=PATH install binaries in PATH"
|
||||
echo " --libdir=PATH install libraries in PATH"
|
||||
echo " --sysconfdir=PATH install config in PATH$confsuffix"
|
||||
echo " --localstatedir=PATH install local state in PATH"
|
||||
echo " --with-confsuffix=SUFFIX suffix for QEMU data inside datadir and sysconfdir [$confsuffix]"
|
||||
|
|
|
@ -5,7 +5,7 @@ qemu usb storage emulation
|
|||
QEMU has three devices for usb storage emulation.
|
||||
|
||||
Number one emulates the classic bulk-only transport protocol which is
|
||||
used by 99% of the usb sticks on the marked today and is called
|
||||
used by 99% of the usb sticks on the market today and is called
|
||||
"usb-storage". Usage (hooking up to xhci, other host controllers work
|
||||
too):
|
||||
|
||||
|
@ -36,7 +36,7 @@ It's called "usb-bot". It shares most code with "usb-storage", and
|
|||
the guest will not be able to see the difference. The qemu command
|
||||
line interface is simliar to usb-uas though, i.e. no automatic scsi
|
||||
disk creation. It also features support for up to 16 LUNs. The LUN
|
||||
numbers must be continous, i.e. for three devices you must use 0+1+2.
|
||||
numbers must be continuous, i.e. for three devices you must use 0+1+2.
|
||||
The 0+1+5 numbering from the "usb-uas" example isn't going to work
|
||||
with "usb-bot".
|
||||
|
||||
|
|
|
@ -2887,7 +2887,7 @@ static int gdbserver_open(int port)
|
|||
|
||||
/* allow fast reuse */
|
||||
val = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
|
||||
qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(port);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "exec/memory.h"
|
||||
#include "hw/irq.h"
|
||||
|
||||
/* The CPU is also modeled as an interrupt controller. */
|
||||
/* The CPU is also modelled as an interrupt controller. */
|
||||
#define ARM_PIC_CPU_IRQ 0
|
||||
#define ARM_PIC_CPU_FIQ 1
|
||||
qemu_irq *arm_pic_init_cpu(ARMCPU *cpu);
|
||||
|
|
|
@ -38,7 +38,7 @@ do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0)
|
|||
* bit 0 - 7: offset in configuration space of a given pci device
|
||||
*/
|
||||
|
||||
/* the helper functio to get a PCIDeice* for a given pci address */
|
||||
/* the helper function to get a PCIDevice* for a given pci address */
|
||||
static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
|
||||
{
|
||||
uint8_t bus_num = addr >> 16;
|
||||
|
|
|
@ -117,11 +117,10 @@ DeviceState *qdev_create(BusState *bus, const char *name)
|
|||
if (bus) {
|
||||
error_report("Unknown device '%s' for bus '%s'", name,
|
||||
object_get_typename(OBJECT(bus)));
|
||||
abort();
|
||||
} else {
|
||||
error_report("Unknown device '%s' for default sysbus", name);
|
||||
abort();
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
return dev;
|
||||
|
|
|
@ -763,7 +763,7 @@ static void sdhci_do_adma(SDHCIState *s)
|
|||
}
|
||||
}
|
||||
|
||||
/* we have unfinished bussiness - reschedule to continue ADMA */
|
||||
/* we have unfinished business - reschedule to continue ADMA */
|
||||
qemu_mod_timer(s->transfer_timer,
|
||||
qemu_get_clock_ns(vm_clock) + SDHC_TRANSFER_DELAY);
|
||||
}
|
||||
|
|
|
@ -306,7 +306,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|||
SerialState *s = opaque;
|
||||
|
||||
addr &= 7;
|
||||
DPRINTF("write addr=0x%02x val=0x%02x\n", addr, val);
|
||||
DPRINTF("write addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 "\n", addr, val);
|
||||
switch(addr) {
|
||||
default:
|
||||
case 0:
|
||||
|
@ -527,7 +527,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
|
|||
ret = s->scr;
|
||||
break;
|
||||
}
|
||||
DPRINTF("read addr=0x%02x val=0x%02x\n", addr, ret);
|
||||
DPRINTF("read addr=0x%" HWADDR_PRIx " val=0x%02x\n", addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ typedef struct InterfaceInfo InterfaceInfo;
|
|||
* Methods are always <emphasis>virtual</emphasis>. Overriding a method in
|
||||
* #TypeInfo.class_init of a subclass leads to any user of the class obtained
|
||||
* via OBJECT_GET_CLASS() accessing the overridden function.
|
||||
* The original function is not automatically invoked. It is the responsability
|
||||
* The original function is not automatically invoked. It is the responsibility
|
||||
* of the overriding class to determine whether and when to invoke the method
|
||||
* being overridden.
|
||||
*
|
||||
|
|
2
memory.c
2
memory.c
|
@ -1321,7 +1321,7 @@ static void memory_region_add_subregion_common(MemoryRegion *mr,
|
|||
if (subregion->may_overlap || other->may_overlap) {
|
||||
continue;
|
||||
}
|
||||
if (int128_gt(int128_make64(offset),
|
||||
if (int128_ge(int128_make64(offset),
|
||||
int128_add(int128_make64(other->addr), other->size))
|
||||
|| int128_le(int128_add(int128_make64(offset), subregion->size),
|
||||
int128_make64(other->addr))) {
|
||||
|
|
|
@ -3560,10 +3560,10 @@ static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
|
|||
* If @cmdline is blank, return NULL.
|
||||
* If it can't be parsed, report to @mon, and return NULL.
|
||||
* Else, insert command arguments into @qdict, and return the command.
|
||||
* If sub-command table exist, and if @cmdline contains addtional string for
|
||||
* sub-command, this function will try search sub-command table. if no
|
||||
* addtional string for sub-command exist, this function will return the found
|
||||
* one in @table.
|
||||
* If a sub-command table exists, and if @cmdline contains an additional string
|
||||
* for a sub-command, this function will try to search the sub-command table.
|
||||
* If no additional string for a sub-command is present, this function will
|
||||
* return the command found in @table.
|
||||
* Do not assume the returned command points into @table! It doesn't
|
||||
* when the command is a sub-command.
|
||||
*/
|
||||
|
|
21
net/socket.c
21
net/socket.c
|
@ -262,8 +262,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
|
|||
}
|
||||
|
||||
val = 1;
|
||||
ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const char *)&val, sizeof(val));
|
||||
ret = qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
if (ret < 0) {
|
||||
perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
|
||||
goto fail;
|
||||
|
@ -283,8 +282,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
|
|||
imr.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
|
||||
ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
(const char *)&imr, sizeof(struct ip_mreq));
|
||||
ret = qemu_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
&imr, sizeof(struct ip_mreq));
|
||||
if (ret < 0) {
|
||||
perror("setsockopt(IP_ADD_MEMBERSHIP)");
|
||||
goto fail;
|
||||
|
@ -292,8 +291,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
|
|||
|
||||
/* Force mcast msgs to loopback (eg. several QEMUs in same host */
|
||||
loop = 1;
|
||||
ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
(const char *)&loop, sizeof(loop));
|
||||
ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
&loop, sizeof(loop));
|
||||
if (ret < 0) {
|
||||
perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
|
||||
goto fail;
|
||||
|
@ -301,8 +300,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
|
|||
|
||||
/* If a bind address is given, only send packets from that address */
|
||||
if (localaddr != NULL) {
|
||||
ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
|
||||
(const char *)localaddr, sizeof(*localaddr));
|
||||
ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
|
||||
localaddr, sizeof(*localaddr));
|
||||
if (ret < 0) {
|
||||
perror("setsockopt(IP_MULTICAST_IF)");
|
||||
goto fail;
|
||||
|
@ -521,7 +520,7 @@ static int net_socket_listen_init(NetClientState *peer,
|
|||
|
||||
/* allow fast reuse */
|
||||
val = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
|
||||
qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
|
||||
ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
|
||||
if (ret < 0) {
|
||||
|
@ -659,8 +658,8 @@ static int net_socket_udp_init(NetClientState *peer,
|
|||
return -1;
|
||||
}
|
||||
val = 1;
|
||||
ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const char *)&val, sizeof(val));
|
||||
ret = qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
&val, sizeof(val));
|
||||
if (ret < 0) {
|
||||
perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
|
||||
closesocket(fd);
|
||||
|
|
|
@ -696,7 +696,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
|
|||
/* QEMU vlans does not support multiqueue tap, in this case peer is set.
|
||||
* For -netdev, peer is always NULL. */
|
||||
if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) {
|
||||
error_report("Multiqueue tap cannnot be used with QEMU vlans");
|
||||
error_report("Multiqueue tap cannot be used with QEMU vlans");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1123,7 +1123,7 @@ is a TCP port number, not a display number.
|
|||
@item websocket
|
||||
|
||||
Opens an additional TCP listening port dedicated to VNC Websocket connections.
|
||||
By defintion the Websocket port is 5700+@var{display}. If @var{host} is
|
||||
By definition the Websocket port is 5700+@var{display}. If @var{host} is
|
||||
specified connections will only be allowed from this host.
|
||||
As an alternative the Websocket port could be specified by using
|
||||
@code{websocket}=@var{port}.
|
||||
|
|
|
@ -120,7 +120,7 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
|
|||
return;
|
||||
}
|
||||
|
||||
/* succeded */
|
||||
/* succeeded */
|
||||
}
|
||||
|
||||
int64_t qmp_guest_get_time(Error **errp)
|
||||
|
|
|
@ -212,9 +212,9 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
|
|||
} while (so->s < 0 && errno == EINTR);
|
||||
closesocket(s);
|
||||
opt = 1;
|
||||
setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int));
|
||||
qemu_setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
|
||||
opt = 1;
|
||||
setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int));
|
||||
qemu_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
|
||||
socket_set_nonblock(so->s);
|
||||
|
||||
/* Append the telnet options now */
|
||||
|
|
|
@ -627,7 +627,7 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
|
|||
addr.sin_port = hport;
|
||||
|
||||
if (((s = qemu_socket(AF_INET,SOCK_STREAM,0)) < 0) ||
|
||||
(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
|
||||
(qemu_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) < 0) ||
|
||||
(bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
|
||||
(listen(s,1) < 0)) {
|
||||
int tmperrno = errno; /* Don't clobber the real reason we failed */
|
||||
|
@ -642,7 +642,7 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
|
|||
#endif
|
||||
return NULL;
|
||||
}
|
||||
setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
|
||||
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
|
||||
|
||||
getsockname(s,(struct sockaddr *)&addr,&addrlen);
|
||||
so->so_fport = addr.sin_port;
|
||||
|
|
|
@ -338,9 +338,9 @@ int tcp_fconnect(struct socket *so)
|
|||
|
||||
socket_set_nonblock(s);
|
||||
opt = 1;
|
||||
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
|
||||
qemu_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
opt = 1;
|
||||
setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
|
||||
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
|
||||
|
@ -427,9 +427,9 @@ void tcp_connect(struct socket *inso)
|
|||
}
|
||||
socket_set_nonblock(s);
|
||||
opt = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int));
|
||||
qemu_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
|
||||
opt = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int));
|
||||
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
|
||||
socket_set_nodelay(s);
|
||||
|
||||
so->so_fport = addr.sin_port;
|
||||
|
|
|
@ -372,7 +372,7 @@ udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
|
|||
udp_detach(so);
|
||||
return NULL;
|
||||
}
|
||||
setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
|
||||
qemu_setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
|
||||
|
||||
getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
|
||||
so->so_fport = addr.sin_port;
|
||||
|
|
|
@ -4746,7 +4746,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
}
|
||||
s->pc++;
|
||||
|
||||
/* 4.1.1-4.1.3: No preceeding lock, 66, f2, f3, or rex prefixes. */
|
||||
/* 4.1.1-4.1.3: No preceding lock, 66, f2, f3, or rex prefixes. */
|
||||
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ
|
||||
| PREFIX_LOCK | PREFIX_DATA)) {
|
||||
goto illegal_op;
|
||||
|
|
|
@ -1142,7 +1142,7 @@ struct DisasInsn {
|
|||
};
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Miscelaneous helpers, used by several operations. */
|
||||
/* Miscellaneous helpers, used by several operations. */
|
||||
|
||||
static void help_l2_shift(DisasContext *s, DisasFields *f,
|
||||
DisasOps *o, int mask)
|
||||
|
|
14
tcg/README
14
tcg/README
|
@ -14,6 +14,10 @@ the emulated architecture. As TCG started as a generic C backend used
|
|||
for cross compiling, it is assumed that the TCG target is different
|
||||
from the host, although it is never the case for QEMU.
|
||||
|
||||
In this document, we use "guest" to specify what architecture we are
|
||||
emulating; "target" always means the TCG target, the machine on which
|
||||
we are running QEMU.
|
||||
|
||||
A TCG "function" corresponds to a QEMU Translated Block (TB).
|
||||
|
||||
A TCG "temporary" is a variable only live in a basic
|
||||
|
@ -379,7 +383,7 @@ double-word product T0. The later is returned in two single-word outputs.
|
|||
|
||||
Similar to mulu2, except the two inputs T1 and T2 are signed.
|
||||
|
||||
********* 64-bit target on 32-bit host support
|
||||
********* 64-bit guest on 32-bit host support
|
||||
|
||||
The following opcodes are internal to TCG. Thus they are to be implemented by
|
||||
32-bit host code generators, but are not to be emitted by guest translators.
|
||||
|
@ -521,9 +525,9 @@ register.
|
|||
a better generated code, but it reduces the memory usage of TCG and
|
||||
the speed of the translation.
|
||||
|
||||
- Don't hesitate to use helpers for complicated or seldom used target
|
||||
- Don't hesitate to use helpers for complicated or seldom used guest
|
||||
instructions. There is little performance advantage in using TCG to
|
||||
implement target instructions taking more than about twenty TCG
|
||||
implement guest instructions taking more than about twenty TCG
|
||||
instructions. Note that this rule of thumb is more applicable to
|
||||
helpers doing complex logic or arithmetic, where the C compiler has
|
||||
scope to do a good job of optimisation; it is less relevant where
|
||||
|
@ -531,9 +535,9 @@ register.
|
|||
inline TCG may still be faster for longer sequences.
|
||||
|
||||
- The hard limit on the number of TCG instructions you can generate
|
||||
per target instruction is set by MAX_OP_PER_INSTR in exec-all.h --
|
||||
per guest instruction is set by MAX_OP_PER_INSTR in exec-all.h --
|
||||
you cannot exceed this without risking a buffer overrun.
|
||||
|
||||
- Use the 'discard' instruction if you know that TCG won't be able to
|
||||
prove that a given global is "dead" at a given program point. The
|
||||
x86 target uses it to improve the condition codes optimisation.
|
||||
x86 guest uses it to improve the condition codes optimisation.
|
||||
|
|
|
@ -156,12 +156,12 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
|
|||
continue;
|
||||
}
|
||||
|
||||
setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
|
||||
qemu_setsockopt(slisten, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (e->ai_family == PF_INET6) {
|
||||
/* listen on both ipv4 and ipv6 */
|
||||
setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,
|
||||
sizeof(off));
|
||||
qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &off,
|
||||
sizeof(off));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -229,7 +229,7 @@ static void wait_for_connect(void *opaque)
|
|||
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
|
||||
|
||||
do {
|
||||
rc = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
|
||||
rc = qemu_getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &val, &valsize);
|
||||
} while (rc == -1 && socket_error() == EINTR);
|
||||
|
||||
/* update rc to contain error */
|
||||
|
@ -456,7 +456,7 @@ int inet_dgram_opts(QemuOpts *opts, Error **errp)
|
|||
error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
|
||||
goto err;
|
||||
}
|
||||
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
|
||||
qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
|
||||
/* bind socket */
|
||||
if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
|
||||
|
|
Loading…
Reference in New Issue